Use glamour and termev to render/colorize content (#181)

Merge branch 'master' into use-glamour

select Glamour Theme based on BackgroundColor

Merge branch 'master' into use-glamour

Merge branch 'master' into use-glamour

update termev

update go.mod

label color colorate

use glamour for issue content

Vendor: Add glamour

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/181
Reviewed-by: techknowlogick <techknowlogick@gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
6543
2020-09-19 16:00:50 +00:00
committed by Lunny Xiao
parent f8d983b523
commit 89e93d90b3
434 changed files with 68002 additions and 3 deletions

1
vendor/github.com/charmbracelet/glamour/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
cmd/

21
vendor/github.com/charmbracelet/glamour/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Charmbracelet, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

72
vendor/github.com/charmbracelet/glamour/README.md generated vendored Normal file
View File

@@ -0,0 +1,72 @@
# Glamour
[![Latest Release](https://img.shields.io/github/release/charmbracelet/glamour.svg)](https://github.com/charmbracelet/glamour/releases)
[![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](https://pkg.go.dev/github.com/charmbracelet/glamour?tab=doc)
[![Build Status](https://github.com/charmbracelet/glamour/workflows/build/badge.svg)](https://github.com/charmbracelet/glamour/actions)
[![Coverage Status](https://coveralls.io/repos/github/charmbracelet/glamour/badge.svg?branch=master)](https://coveralls.io/github/charmbracelet/glamour?branch=master)
[![Go ReportCard](http://goreportcard.com/badge/charmbracelet/glamour)](http://goreportcard.com/report/charmbracelet/glamour)
Write handsome command-line tools with *glamour*!
`glamour` lets you render [markdown](https://en.wikipedia.org/wiki/Markdown)
documents & templates on [ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code)
compatible terminals. You can create your own stylesheet or use one of our
glamourous default themes.
## Usage
```go
import "github.com/charmbracelet/glamour"
in := `# Hello World
This is a simple example of glamour!
Check out the [other examples](https://github.com/charmbracelet/glamour/tree/master/examples).
Bye!
`
out, err := glamour.Render(in, "dark")
fmt.Print(out)
```
![HelloWorld Example](https://github.com/charmbracelet/glamour/raw/master/examples/helloworld/helloworld.png)
### Custom Renderer
```go
import "github.com/charmbracelet/glamour"
r, _ := glamour.NewTermRenderer(
// detect background color and pick either the default dark or light theme
glamour.WithAutoStyle(),
// wrap output at specific width
glamour.WithWordWrap(40),
)
out, err := r.Render(in)
fmt.Print(out)
```
## Styles
You can find all available default styles in our [gallery](https://github.com/charmbracelet/glamour/tree/master/styles/gallery).
Want to create your own style? [Learn how!](https://github.com/charmbracelet/glamour/tree/master/styles)
There are a few options for using a custom style:
1. Call `glamour.Render(inputText, "desiredStyle")`
1. Set the `GLAMOUR_STYLE` environment variable to your desired default style or a file location for a style and call `glamour.RenderWithEnvironmentConfig(inputText)`
1. Set the `GLAMOUR_STYLE` environment variable and pass `glamour.WithEnvironmentConfig()` to your custom renderer
## Glamourous Projects
Check out [Glow](https://github.com/charmbracelet/glow), a markdown renderer for
the command-line, which uses `glamour`.
## License
[MIT](https://github.com/charmbracelet/glamour/raw/master/LICENSE)

View File

@@ -0,0 +1,104 @@
package ansi
import (
"bytes"
"io"
"text/template"
"github.com/muesli/termenv"
)
// BaseElement renders a styled primitive element.
type BaseElement struct {
Token string
Prefix string
Suffix string
Style StylePrimitive
}
func formatToken(format string, token string) (string, error) {
var b bytes.Buffer
v := make(map[string]interface{})
v["text"] = token
tmpl, err := template.New(format).Funcs(TemplateFuncMap).Parse(format)
if err != nil {
return "", err
}
err = tmpl.Execute(&b, v)
return b.String(), err
}
func renderText(w io.Writer, p termenv.Profile, rules StylePrimitive, s string) {
if len(s) == 0 {
return
}
out := termenv.String(s)
if rules.Color != nil {
out = out.Foreground(p.Color(*rules.Color))
}
if rules.BackgroundColor != nil {
out = out.Background(p.Color(*rules.BackgroundColor))
}
if rules.Underline != nil && *rules.Underline {
out = out.Underline()
}
if rules.Bold != nil && *rules.Bold {
out = out.Bold()
}
if rules.Italic != nil && *rules.Italic {
out = out.Italic()
}
if rules.CrossedOut != nil && *rules.CrossedOut {
out = out.CrossOut()
}
if rules.Overlined != nil && *rules.Overlined {
out = out.Overline()
}
if rules.Inverse != nil && *rules.Inverse {
out = out.Reverse()
}
if rules.Blink != nil && *rules.Blink {
out = out.Blink()
}
_, _ = w.Write([]byte(out.String()))
}
func (e *BaseElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Prefix)
defer func() {
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Suffix)
}()
rules := bs.With(e.Style)
// render unstyled prefix/suffix
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockPrefix)
defer func() {
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockSuffix)
}()
// render styled prefix/suffix
renderText(w, ctx.options.ColorProfile, rules, rules.Prefix)
defer func() {
renderText(w, ctx.options.ColorProfile, rules, rules.Suffix)
}()
s := e.Token
if len(rules.Format) > 0 {
var err error
s, err = formatToken(rules.Format, s)
if err != nil {
return err
}
}
renderText(w, ctx.options.ColorProfile, rules, s)
return nil
}

View File

@@ -0,0 +1,59 @@
package ansi
import (
"bytes"
"io"
"github.com/muesli/reflow/wordwrap"
)
// BlockElement provides a render buffer for children of a block element.
// After all children have been rendered into it, it applies indentation and
// margins around them and writes everything to the parent rendering buffer.
type BlockElement struct {
Block *bytes.Buffer
Style StyleBlock
Margin bool
Newline bool
}
func (e *BlockElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
bs.Push(*e)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, e.Style.BlockPrefix)
renderText(bs.Current().Block, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Style.Prefix)
return nil
}
func (e *BlockElement) Finish(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
if e.Margin {
mw := NewMarginWriter(ctx, w, bs.Current().Style)
_, err := mw.Write(
wordwrap.Bytes(bs.Current().Block.Bytes(), int(bs.Width(ctx))))
if err != nil {
return err
}
if e.Newline {
_, err = mw.Write([]byte("\n"))
if err != nil {
return err
}
}
} else {
_, err := bs.Parent().Block.Write(bs.Current().Block.Bytes())
if err != nil {
return err
}
}
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, e.Style.Suffix)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, e.Style.BlockSuffix)
bs.Current().Block.Reset()
bs.Pop()
return nil
}

View File

@@ -0,0 +1,95 @@
package ansi
import (
"bytes"
)
// BlockStack is a stack of block elements, used to calculate the current
// indentation & margin level during the rendering process.
type BlockStack []BlockElement
// Len returns the length of the stack.
func (s *BlockStack) Len() int {
return len(*s)
}
// Push appends an item to the stack.
func (s *BlockStack) Push(e BlockElement) {
*s = append(*s, e)
}
// Pop removes the last item on the stack.
func (s *BlockStack) Pop() {
stack := *s
if len(stack) == 0 {
return
}
stack = stack[0 : len(stack)-1]
*s = stack
}
// Indent returns the current indentation level of all elements in the stack.
func (s BlockStack) Indent() uint {
var i uint
for _, v := range s {
if v.Style.Indent == nil {
continue
}
i += *v.Style.Indent
}
return i
}
// Margin returns the current margin level of all elements in the stack.
func (s BlockStack) Margin() uint {
var i uint
for _, v := range s {
if v.Style.Margin == nil {
continue
}
i += *v.Style.Margin
}
return i
}
// Width returns the available rendering width
func (s BlockStack) Width(ctx RenderContext) uint {
if s.Indent()+s.Margin()*2 > uint(ctx.options.WordWrap) {
return 0
}
return uint(ctx.options.WordWrap) - s.Indent() - s.Margin()*2
}
// Parent returns the current BlockElement's parent.
func (s BlockStack) Parent() BlockElement {
if len(s) == 1 {
return BlockElement{
Block: &bytes.Buffer{},
}
}
return s[len(s)-2]
}
// Current returns the current BlockElement.
func (s BlockStack) Current() BlockElement {
if len(s) == 0 {
return BlockElement{
Block: &bytes.Buffer{},
}
}
return s[len(s)-1]
}
// With returns a StylePrimitive that inherits the current BlockElement's style.
func (s BlockStack) With(child StylePrimitive) StylePrimitive {
sb := StyleBlock{}
sb.StylePrimitive = child
return cascadeStyle(s.Current().Style, sb, false).StylePrimitive
}

View File

@@ -0,0 +1,125 @@
package ansi
import (
"io"
"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/quick"
"github.com/alecthomas/chroma/styles"
"github.com/muesli/reflow/indent"
)
// A CodeBlockElement is used to render code blocks.
type CodeBlockElement struct {
Code string
Language string
}
func chromaStyle(style StylePrimitive) string {
var s string
if style.Color != nil {
s = *style.Color
}
if style.BackgroundColor != nil {
if s != "" {
s += " "
}
s += "bg:" + *style.BackgroundColor
}
if style.Italic != nil && *style.Italic {
if s != "" {
s += " "
}
s += "italic"
}
if style.Bold != nil && *style.Bold {
if s != "" {
s += " "
}
s += "bold"
}
if style.Underline != nil && *style.Underline {
if s != "" {
s += " "
}
s += "underline"
}
return s
}
func (e *CodeBlockElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
var indentation uint
var margin uint
rules := ctx.options.Styles.CodeBlock
if rules.Indent != nil {
indentation = *rules.Indent
}
if rules.Margin != nil {
margin = *rules.Margin
}
theme := rules.Theme
if rules.Chroma != nil && ctx.options.ColorProfile > 1 {
theme = "charm"
styles.Register(chroma.MustNewStyle("charm",
chroma.StyleEntries{
chroma.Text: chromaStyle(rules.Chroma.Text),
chroma.Error: chromaStyle(rules.Chroma.Error),
chroma.Comment: chromaStyle(rules.Chroma.Comment),
chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
chroma.Operator: chromaStyle(rules.Chroma.Operator),
chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
chroma.Name: chromaStyle(rules.Chroma.Name),
chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
chroma.NameException: chromaStyle(rules.Chroma.NameException),
chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
chroma.Literal: chromaStyle(rules.Chroma.Literal),
chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
chroma.Background: chromaStyle(rules.Chroma.Background),
}))
}
iw := indent.NewWriterPipe(w, indentation+margin, func(wr io.Writer) {
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, " ")
})
if len(theme) > 0 {
renderText(iw, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockPrefix)
err := quick.Highlight(iw, e.Code, e.Language, "terminal256", theme)
if err != nil {
return err
}
renderText(iw, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockSuffix)
return nil
}
// fallback rendering
el := &BaseElement{
Token: e.Code,
Style: rules.StylePrimitive,
}
return el.Render(iw, ctx)
}

View File

@@ -0,0 +1,38 @@
package ansi
import (
"html"
"strings"
"github.com/microcosm-cc/bluemonday"
)
// RenderContext holds the current rendering options and state.
type RenderContext struct {
options Options
blockStack *BlockStack
table *TableElement
stripper *bluemonday.Policy
}
// NewRenderContext returns a new RenderContext.
func NewRenderContext(options Options) RenderContext {
return RenderContext{
options: options,
blockStack: &BlockStack{},
table: &TableElement{},
stripper: bluemonday.StrictPolicy(),
}
}
// SanitizeHTML sanitizes HTML content.
func (ctx RenderContext) SanitizeHTML(s string, trimSpaces bool) string {
s = ctx.stripper.Sanitize(s)
if trimSpaces {
s = strings.TrimSpace(s)
}
return html.UnescapeString(s)
}

View File

@@ -0,0 +1,401 @@
package ansi
import (
"bytes"
"fmt"
"html"
"io"
"strings"
"github.com/yuin/goldmark/ast"
astext "github.com/yuin/goldmark/extension/ast"
)
// ElementRenderer is called when entering a markdown node.
type ElementRenderer interface {
Render(w io.Writer, ctx RenderContext) error
}
// ElementFinisher is called when leaving a markdown node.
type ElementFinisher interface {
Finish(w io.Writer, ctx RenderContext) error
}
// An Element is used to instruct the renderer how to handle individual markdown
// nodes.
type Element struct {
Entering string
Exiting string
Renderer ElementRenderer
Finisher ElementFinisher
}
// NewElement returns the appropriate render Element for a given node.
func (tr *ANSIRenderer) NewElement(node ast.Node, source []byte) Element {
ctx := tr.context
// fmt.Print(strings.Repeat(" ", ctx.blockStack.Len()), node.Type(), node.Kind())
// defer fmt.Println()
switch node.Kind() {
// Document
case ast.KindDocument:
e := &BlockElement{
Block: &bytes.Buffer{},
Style: ctx.options.Styles.Document,
Margin: true,
}
return Element{
Renderer: e,
Finisher: e,
}
// Heading
case ast.KindHeading:
n := node.(*ast.Heading)
he := &HeadingElement{
Level: n.Level,
First: node.PreviousSibling() == nil,
}
return Element{
Exiting: "",
Renderer: he,
Finisher: he,
}
// Paragraph
case ast.KindParagraph:
if node.Parent() != nil && node.Parent().Kind() == ast.KindListItem {
return Element{}
}
return Element{
Renderer: &ParagraphElement{
First: node.PreviousSibling() == nil,
},
Finisher: &ParagraphElement{},
}
// Blockquote
case ast.KindBlockquote:
e := &BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.BlockQuote, false),
Margin: true,
Newline: true,
}
return Element{
Entering: "\n",
Renderer: e,
Finisher: e,
}
// Lists
case ast.KindList:
s := ctx.options.Styles.List.StyleBlock
if s.Indent == nil {
var i uint
s.Indent = &i
}
n := node.Parent()
for n != nil {
if n.Kind() == ast.KindList {
i := ctx.options.Styles.List.LevelIndent
s.Indent = &i
break
}
n = n.Parent()
}
e := &BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, s, false),
Margin: true,
Newline: true,
}
return Element{
Entering: "\n",
Renderer: e,
Finisher: e,
}
case ast.KindListItem:
var l uint
var e uint
l = 1
n := node
for n.PreviousSibling() != nil && (n.PreviousSibling().Kind() == ast.KindListItem) {
l++
n = n.PreviousSibling()
}
if node.Parent().(*ast.List).IsOrdered() {
e = l
}
post := "\n"
if (node.LastChild() != nil && node.LastChild().Kind() == ast.KindList) ||
node.NextSibling() == nil {
post = ""
}
if node.FirstChild() != nil &&
node.FirstChild().FirstChild() != nil &&
node.FirstChild().FirstChild().Kind() == astext.KindTaskCheckBox {
nc := node.FirstChild().FirstChild().(*astext.TaskCheckBox)
return Element{
Exiting: post,
Renderer: &TaskElement{
Checked: nc.IsChecked,
},
}
}
return Element{
Exiting: post,
Renderer: &ItemElement{
Enumeration: e,
},
}
// Text Elements
case ast.KindText:
n := node.(*ast.Text)
s := string(n.Segment.Value(source))
if n.HardLineBreak() || (n.SoftLineBreak()) {
s += "\n"
}
return Element{
Renderer: &BaseElement{
Token: html.UnescapeString(s),
Style: ctx.options.Styles.Text,
},
}
case ast.KindEmphasis:
n := node.(*ast.Emphasis)
s := string(n.Text(source))
style := ctx.options.Styles.Emph
if n.Level > 1 {
style = ctx.options.Styles.Strong
}
return Element{
Renderer: &BaseElement{
Token: html.UnescapeString(s),
Style: style,
},
}
case astext.KindStrikethrough:
n := node.(*astext.Strikethrough)
s := string(n.Text(source))
style := ctx.options.Styles.Strikethrough
return Element{
Renderer: &BaseElement{
Token: html.UnescapeString(s),
Style: style,
},
}
case ast.KindThematicBreak:
return Element{
Entering: "",
Exiting: "",
Renderer: &BaseElement{
Style: ctx.options.Styles.HorizontalRule,
},
}
// Links
case ast.KindLink:
n := node.(*ast.Link)
return Element{
Renderer: &LinkElement{
Text: textFromChildren(node, source),
BaseURL: ctx.options.BaseURL,
URL: string(n.Destination),
},
}
case ast.KindAutoLink:
n := node.(*ast.AutoLink)
u := string(n.URL(source))
label := string(n.Label(source))
if n.AutoLinkType == ast.AutoLinkEmail && !strings.HasPrefix(strings.ToLower(u), "mailto:") {
u = "mailto:" + u
}
return Element{
Renderer: &LinkElement{
Text: label,
BaseURL: ctx.options.BaseURL,
URL: u,
},
}
// Images
case ast.KindImage:
n := node.(*ast.Image)
text := string(n.Text(source))
return Element{
Renderer: &ImageElement{
Text: text,
BaseURL: ctx.options.BaseURL,
URL: string(n.Destination),
},
}
// Code
case ast.KindFencedCodeBlock:
n := node.(*ast.FencedCodeBlock)
l := n.Lines().Len()
s := ""
for i := 0; i < l; i++ {
line := n.Lines().At(i)
s += string(line.Value(source))
}
return Element{
Entering: "\n",
Renderer: &CodeBlockElement{
Code: s,
Language: string(n.Language(source)),
},
}
case ast.KindCodeBlock:
n := node.(*ast.CodeBlock)
l := n.Lines().Len()
s := ""
for i := 0; i < l; i++ {
line := n.Lines().At(i)
s += string(line.Value(source))
}
return Element{
Entering: "\n",
Renderer: &CodeBlockElement{
Code: s,
},
}
case ast.KindCodeSpan:
// n := node.(*ast.CodeSpan)
e := &BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.Code, false),
}
return Element{
Renderer: e,
Finisher: e,
}
// Tables
case astext.KindTable:
te := &TableElement{}
return Element{
Entering: "\n",
Renderer: te,
Finisher: te,
}
case astext.KindTableCell:
s := ""
n := node.FirstChild()
for n != nil {
s += string(n.Text(source))
// s += string(n.LinkData.Destination)
n = n.NextSibling()
}
return Element{
Renderer: &TableCellElement{
Text: s,
Head: node.Parent().Kind() == astext.KindTableHeader,
},
}
case astext.KindTableHeader:
return Element{
Finisher: &TableHeadElement{},
}
case astext.KindTableRow:
return Element{
Finisher: &TableRowElement{},
}
// HTML Elements
case ast.KindHTMLBlock:
n := node.(*ast.HTMLBlock)
return Element{
Renderer: &BaseElement{
Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n",
Style: ctx.options.Styles.HTMLBlock.StylePrimitive,
},
}
case ast.KindRawHTML:
n := node.(*ast.RawHTML)
return Element{
Renderer: &BaseElement{
Token: ctx.SanitizeHTML(string(n.Text(source)), true),
Style: ctx.options.Styles.HTMLSpan.StylePrimitive,
},
}
// Definition Lists
case astext.KindDefinitionList:
e := &BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.DefinitionList, false),
Margin: true,
Newline: true,
}
return Element{
Entering: "\n",
Renderer: e,
Finisher: e,
}
case astext.KindDefinitionTerm:
return Element{
Renderer: &BaseElement{
Style: ctx.options.Styles.DefinitionTerm,
},
}
case astext.KindDefinitionDescription:
return Element{
Renderer: &BaseElement{
Style: ctx.options.Styles.DefinitionDescription,
},
}
// Handled by parents
case astext.KindTaskCheckBox:
// handled by KindListItem
return Element{}
case ast.KindTextBlock:
return Element{}
// Unknown case
default:
fmt.Println("Warning: unhandled element", node.Kind().String())
return Element{}
}
}
func textFromChildren(node ast.Node, source []byte) string {
var s string
for c := node.FirstChild(); c != nil; c = c.NextSibling() {
if c.Kind() == ast.KindText {
cn := c.(*ast.Text)
s += string(cn.Segment.Value(source))
if cn.HardLineBreak() || (cn.SoftLineBreak()) {
s += "\n"
}
} else {
s += string(c.Text(source))
}
}
return s
}

View File

@@ -0,0 +1,86 @@
package ansi
import (
"bytes"
"io"
"github.com/muesli/reflow/indent"
"github.com/muesli/reflow/wordwrap"
)
// A HeadingElement is used to render headings.
type HeadingElement struct {
Level int
First bool
}
func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
rules := ctx.options.Styles.Heading
switch e.Level {
case 1:
rules = cascadeStyles(true, rules, ctx.options.Styles.H1)
case 2:
rules = cascadeStyles(true, rules, ctx.options.Styles.H2)
case 3:
rules = cascadeStyles(true, rules, ctx.options.Styles.H3)
case 4:
rules = cascadeStyles(true, rules, ctx.options.Styles.H4)
case 5:
rules = cascadeStyles(true, rules, ctx.options.Styles.H5)
case 6:
rules = cascadeStyles(true, rules, ctx.options.Styles.H6)
}
if !e.First {
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, "\n")
}
be := BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(bs.Current().Style, rules, false),
}
bs.Push(be)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockPrefix)
renderText(bs.Current().Block, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Prefix)
return nil
}
func (e *HeadingElement) Finish(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
rules := bs.Current().Style
var indentation uint
var margin uint
if rules.Indent != nil {
indentation = *rules.Indent
}
if rules.Margin != nil {
margin = *rules.Margin
}
iw := indent.NewWriterPipe(w, indentation+margin, func(wr io.Writer) {
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, " ")
})
flow := wordwrap.NewWriter(int(bs.Width(ctx) - indentation - margin*2))
_, err := flow.Write(bs.Current().Block.Bytes())
if err != nil {
return err
}
flow.Close()
_, err = iw.Write(flow.Bytes())
if err != nil {
return err
}
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Suffix)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockSuffix)
bs.Current().Block.Reset()
bs.Pop()
return nil
}

39
vendor/github.com/charmbracelet/glamour/ansi/image.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package ansi
import (
"io"
)
// An ImageElement is used to render images elements.
type ImageElement struct {
Text string
BaseURL string
URL string
Child ElementRenderer // FIXME
}
func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error {
if len(e.Text) > 0 {
el := &BaseElement{
Token: e.Text,
Style: ctx.options.Styles.ImageText,
}
err := el.Render(w, ctx)
if err != nil {
return err
}
}
if len(e.URL) > 0 {
el := &BaseElement{
Token: resolveRelativeURL(e.BaseURL, e.URL),
Prefix: " ",
Style: ctx.options.Styles.Image,
}
err := el.Render(w, ctx)
if err != nil {
return err
}
}
return nil
}

78
vendor/github.com/charmbracelet/glamour/ansi/link.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
package ansi
import (
"io"
"net/url"
)
// A LinkElement is used to render hyperlinks.
type LinkElement struct {
Text string
BaseURL string
URL string
Child ElementRenderer // FIXME
}
func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error {
var textRendered bool
if len(e.Text) > 0 && e.Text != e.URL {
textRendered = true
el := &BaseElement{
Token: e.Text,
Style: ctx.options.Styles.LinkText,
}
err := el.Render(w, ctx)
if err != nil {
return err
}
}
/*
if node.LastChild != nil {
if node.LastChild.Type == bf.Image {
el := tr.NewElement(node.LastChild)
err := el.Renderer.Render(w, node.LastChild, tr)
if err != nil {
return err
}
}
if len(node.LastChild.Literal) > 0 &&
string(node.LastChild.Literal) != string(node.LinkData.Destination) {
textRendered = true
el := &BaseElement{
Token: string(node.LastChild.Literal),
Style: ctx.style[LinkText],
}
err := el.Render(w, node.LastChild, tr)
if err != nil {
return err
}
}
}
*/
u, err := url.Parse(e.URL)
if err == nil &&
"#"+u.Fragment != e.URL { // if the URL only consists of an anchor, ignore it
pre := " "
style := ctx.options.Styles.Link
if !textRendered {
pre = ""
style.BlockPrefix = ""
style.BlockSuffix = ""
}
el := &BaseElement{
Token: resolveRelativeURL(e.BaseURL, e.URL),
Prefix: pre,
Style: style,
}
err := el.Render(w, ctx)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,27 @@
package ansi
import (
"io"
"strconv"
)
// An ItemElement is used to render items inside a list.
type ItemElement struct {
Enumeration uint
}
func (e *ItemElement) Render(w io.Writer, ctx RenderContext) error {
var el *BaseElement
if e.Enumeration > 0 {
el = &BaseElement{
Style: ctx.options.Styles.Enumeration,
Prefix: strconv.FormatInt(int64(e.Enumeration), 10),
}
} else {
el = &BaseElement{
Style: ctx.options.Styles.Item,
}
}
return el.Render(w, ctx)
}

52
vendor/github.com/charmbracelet/glamour/ansi/margin.go generated vendored Normal file
View File

@@ -0,0 +1,52 @@
package ansi
import (
"io"
"github.com/muesli/reflow/indent"
"github.com/muesli/reflow/padding"
)
// MarginWriter is a Writer that applies indentation and padding around
// whatever you write to it.
type MarginWriter struct {
w io.Writer
pw *padding.Writer
iw *indent.Writer
}
// NewMarginWriter returns a new MarginWriter.
func NewMarginWriter(ctx RenderContext, w io.Writer, rules StyleBlock) *MarginWriter {
bs := ctx.blockStack
var indentation uint
var margin uint
if rules.Indent != nil {
indentation = *rules.Indent
}
if rules.Margin != nil {
margin = *rules.Margin
}
pw := padding.NewWriterPipe(w, bs.Width(ctx), func(wr io.Writer) {
renderText(w, ctx.options.ColorProfile, rules.StylePrimitive, " ")
})
ic := " "
if rules.IndentToken != nil {
ic = *rules.IndentToken
}
iw := indent.NewWriterPipe(pw, indentation+margin, func(wr io.Writer) {
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, ic)
})
return &MarginWriter{
w: w,
pw: pw,
iw: iw,
}
}
func (w *MarginWriter) Write(b []byte) (int, error) {
return w.iw.Write(b)
}

View File

@@ -0,0 +1,58 @@
package ansi
import (
"bytes"
"io"
"strings"
"github.com/muesli/reflow/wordwrap"
)
// A ParagraphElement is used to render individual paragraphs.
type ParagraphElement struct {
First bool
}
func (e *ParagraphElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
rules := ctx.options.Styles.Paragraph
if !e.First {
_, _ = w.Write([]byte("\n"))
}
be := BlockElement{
Block: &bytes.Buffer{},
Style: cascadeStyle(bs.Current().Style, rules, false),
}
bs.Push(be)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockPrefix)
renderText(bs.Current().Block, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Prefix)
return nil
}
func (e *ParagraphElement) Finish(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
rules := bs.Current().Style
mw := NewMarginWriter(ctx, w, rules)
if len(strings.TrimSpace(bs.Current().Block.String())) > 0 {
flow := wordwrap.NewWriter(int(bs.Width(ctx)))
flow.KeepNewlines = false
_, _ = flow.Write(bs.Current().Block.Bytes())
flow.Close()
_, err := mw.Write(flow.Bytes())
if err != nil {
return err
}
_, _ = mw.Write([]byte("\n"))
}
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.Suffix)
renderText(w, ctx.options.ColorProfile, bs.Parent().Style.StylePrimitive, rules.BlockSuffix)
bs.Current().Block.Reset()
bs.Pop()
return nil
}

View File

@@ -0,0 +1,163 @@
package ansi
import (
"io"
"net/url"
"strings"
"github.com/muesli/termenv"
"github.com/yuin/goldmark/ast"
astext "github.com/yuin/goldmark/extension/ast"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
)
// Options is used to configure an ANSIRenderer.
type Options struct {
BaseURL string
WordWrap int
ColorProfile termenv.Profile
Styles StyleConfig
}
// ANSIRenderer renders markdown content as ANSI escaped sequences.
type ANSIRenderer struct {
context RenderContext
}
// NewRenderer returns a new ANSIRenderer with style and options set.
func NewRenderer(options Options) *ANSIRenderer {
return &ANSIRenderer{
context: NewRenderContext(options),
}
}
// RegisterFuncs implements NodeRenderer.RegisterFuncs.
func (r *ANSIRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
// blocks
reg.Register(ast.KindDocument, r.renderNode)
reg.Register(ast.KindHeading, r.renderNode)
reg.Register(ast.KindBlockquote, r.renderNode)
reg.Register(ast.KindCodeBlock, r.renderNode)
reg.Register(ast.KindFencedCodeBlock, r.renderNode)
reg.Register(ast.KindHTMLBlock, r.renderNode)
reg.Register(ast.KindList, r.renderNode)
reg.Register(ast.KindListItem, r.renderNode)
reg.Register(ast.KindParagraph, r.renderNode)
reg.Register(ast.KindTextBlock, r.renderNode)
reg.Register(ast.KindThematicBreak, r.renderNode)
// inlines
reg.Register(ast.KindAutoLink, r.renderNode)
reg.Register(ast.KindCodeSpan, r.renderNode)
reg.Register(ast.KindEmphasis, r.renderNode)
reg.Register(ast.KindImage, r.renderNode)
reg.Register(ast.KindLink, r.renderNode)
reg.Register(ast.KindRawHTML, r.renderNode)
reg.Register(ast.KindText, r.renderNode)
reg.Register(ast.KindString, r.renderNode)
// tables
reg.Register(astext.KindTable, r.renderNode)
reg.Register(astext.KindTableHeader, r.renderNode)
reg.Register(astext.KindTableRow, r.renderNode)
reg.Register(astext.KindTableCell, r.renderNode)
// definitions
reg.Register(astext.KindDefinitionList, r.renderNode)
reg.Register(astext.KindDefinitionTerm, r.renderNode)
reg.Register(astext.KindDefinitionDescription, r.renderNode)
// footnotes
reg.Register(astext.KindFootnote, r.renderNode)
reg.Register(astext.KindFootnoteList, r.renderNode)
reg.Register(astext.KindFootnoteLink, r.renderNode)
reg.Register(astext.KindFootnoteBackLink, r.renderNode)
// checkboxes
reg.Register(astext.KindTaskCheckBox, r.renderNode)
// strikethrough
reg.Register(astext.KindStrikethrough, r.renderNode)
}
func (r *ANSIRenderer) renderNode(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
// _, _ = w.Write([]byte(node.Type.String()))
writeTo := io.Writer(w)
bs := r.context.blockStack
// children get rendered by their parent
if isChild(node) {
return ast.WalkContinue, nil
}
e := r.NewElement(node, source)
if entering {
// everything below the Document element gets rendered into a block buffer
if bs.Len() > 0 {
writeTo = io.Writer(bs.Current().Block)
}
_, _ = writeTo.Write([]byte(e.Entering))
if e.Renderer != nil {
err := e.Renderer.Render(writeTo, r.context)
if err != nil {
return ast.WalkStop, err
}
}
} else {
// everything below the Document element gets rendered into a block buffer
if bs.Len() > 0 {
writeTo = io.Writer(bs.Parent().Block)
}
// if we're finished rendering the entire document,
// flush to the real writer
if node.Type() == ast.TypeDocument {
writeTo = w
}
if e.Finisher != nil {
err := e.Finisher.Finish(writeTo, r.context)
if err != nil {
return ast.WalkStop, err
}
}
_, _ = bs.Current().Block.Write([]byte(e.Exiting))
}
return ast.WalkContinue, nil
}
func isChild(node ast.Node) bool {
if node.Parent() != nil && node.Parent().Kind() == ast.KindBlockquote {
// skip paragraph within blockquote to avoid reflowing text
return true
}
for n := node.Parent(); n != nil; n = n.Parent() {
// These types are already rendered by their parent
switch n.Kind() {
case ast.KindLink, ast.KindImage, ast.KindEmphasis, astext.KindStrikethrough, astext.KindTableCell:
return true
}
}
return false
}
func resolveRelativeURL(baseURL string, rel string) string {
u, err := url.Parse(rel)
if err != nil {
return rel
}
if u.IsAbs() {
return rel
}
u.Path = strings.TrimPrefix(u.Path, "/")
base, err := url.Parse(baseURL)
if err != nil {
return rel
}
return base.ResolveReference(u).String()
}

227
vendor/github.com/charmbracelet/glamour/ansi/style.go generated vendored Normal file
View File

@@ -0,0 +1,227 @@
package ansi
// Chroma holds all the chroma settings.
type Chroma struct {
Text StylePrimitive `json:"text,omitempty"`
Error StylePrimitive `json:"error,omitempty"`
Comment StylePrimitive `json:"comment,omitempty"`
CommentPreproc StylePrimitive `json:"comment_preproc,omitempty"`
Keyword StylePrimitive `json:"keyword,omitempty"`
KeywordReserved StylePrimitive `json:"keyword_reserved,omitempty"`
KeywordNamespace StylePrimitive `json:"keyword_namespace,omitempty"`
KeywordType StylePrimitive `json:"keyword_type,omitempty"`
Operator StylePrimitive `json:"operator,omitempty"`
Punctuation StylePrimitive `json:"punctuation,omitempty"`
Name StylePrimitive `json:"name,omitempty"`
NameBuiltin StylePrimitive `json:"name_builtin,omitempty"`
NameTag StylePrimitive `json:"name_tag,omitempty"`
NameAttribute StylePrimitive `json:"name_attribute,omitempty"`
NameClass StylePrimitive `json:"name_class,omitempty"`
NameConstant StylePrimitive `json:"name_constant,omitempty"`
NameDecorator StylePrimitive `json:"name_decorator,omitempty"`
NameException StylePrimitive `json:"name_exception,omitempty"`
NameFunction StylePrimitive `json:"name_function,omitempty"`
NameOther StylePrimitive `json:"name_other,omitempty"`
Literal StylePrimitive `json:"literal,omitempty"`
LiteralNumber StylePrimitive `json:"literal_number,omitempty"`
LiteralDate StylePrimitive `json:"literal_date,omitempty"`
LiteralString StylePrimitive `json:"literal_string,omitempty"`
LiteralStringEscape StylePrimitive `json:"literal_string_escape,omitempty"`
GenericDeleted StylePrimitive `json:"generic_deleted,omitempty"`
GenericEmph StylePrimitive `json:"generic_emph,omitempty"`
GenericInserted StylePrimitive `json:"generic_inserted,omitempty"`
GenericStrong StylePrimitive `json:"generic_strong,omitempty"`
GenericSubheading StylePrimitive `json:"generic_subheading,omitempty"`
Background StylePrimitive `json:"background,omitempty"`
}
// StylePrimitive holds all the basic style settings.
type StylePrimitive struct {
BlockPrefix string `json:"block_prefix,omitempty"`
BlockSuffix string `json:"block_suffix,omitempty"`
Prefix string `json:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty"`
Color *string `json:"color,omitempty"`
BackgroundColor *string `json:"background_color,omitempty"`
Underline *bool `json:"underline,omitempty"`
Bold *bool `json:"bold,omitempty"`
Italic *bool `json:"italic,omitempty"`
CrossedOut *bool `json:"crossed_out,omitempty"`
Faint *bool `json:"faint,omitempty"`
Conceal *bool `json:"conceal,omitempty"`
Overlined *bool `json:"overlined,omitempty"`
Inverse *bool `json:"inverse,omitempty"`
Blink *bool `json:"blink,omitempty"`
Format string `json:"format,omitempty"`
}
// StyleTask holds the style settings for a task item.
type StyleTask struct {
StylePrimitive
Ticked string `json:"ticked,omitempty"`
Unticked string `json:"unticked,omitempty"`
}
// StyleBlock holds the basic style settings for block elements.
type StyleBlock struct {
StylePrimitive
Indent *uint `json:"indent,omitempty"`
IndentToken *string `json:"indent_token,omitempty"`
Margin *uint `json:"margin,omitempty"`
}
// StyleCodeBlock holds the style settings for a code block.
type StyleCodeBlock struct {
StyleBlock
Theme string `json:"theme,omitempty"`
Chroma *Chroma `json:"chroma,omitempty"`
}
// StyleList holds the style settings for a list.
type StyleList struct {
StyleBlock
LevelIndent uint `json:"level_indent,omitempty"`
}
// StyleTable holds the style settings for a table.
type StyleTable struct {
StyleBlock
CenterSeparator *string `json:"center_separator,omitempty"`
ColumnSeparator *string `json:"column_separator,omitempty"`
RowSeparator *string `json:"row_separator,omitempty"`
}
// StyleConfig is used to configure the styling behavior of an ANSIRenderer.
type StyleConfig struct {
Document StyleBlock `json:"document,omitempty"`
BlockQuote StyleBlock `json:"block_quote,omitempty"`
Paragraph StyleBlock `json:"paragraph,omitempty"`
List StyleList `json:"list,omitempty"`
Heading StyleBlock `json:"heading,omitempty"`
H1 StyleBlock `json:"h1,omitempty"`
H2 StyleBlock `json:"h2,omitempty"`
H3 StyleBlock `json:"h3,omitempty"`
H4 StyleBlock `json:"h4,omitempty"`
H5 StyleBlock `json:"h5,omitempty"`
H6 StyleBlock `json:"h6,omitempty"`
Text StylePrimitive `json:"text,omitempty"`
Strikethrough StylePrimitive `json:"strikethrough,omitempty"`
Emph StylePrimitive `json:"emph,omitempty"`
Strong StylePrimitive `json:"strong,omitempty"`
HorizontalRule StylePrimitive `json:"hr,omitempty"`
Item StylePrimitive `json:"item,omitempty"`
Enumeration StylePrimitive `json:"enumeration,omitempty"`
Task StyleTask `json:"task,omitempty"`
Link StylePrimitive `json:"link,omitempty"`
LinkText StylePrimitive `json:"link_text,omitempty"`
Image StylePrimitive `json:"image,omitempty"`
ImageText StylePrimitive `json:"image_text,omitempty"`
Code StyleBlock `json:"code,omitempty"`
CodeBlock StyleCodeBlock `json:"code_block,omitempty"`
Table StyleTable `json:"table,omitempty"`
DefinitionList StyleBlock `json:"definition_list,omitempty"`
DefinitionTerm StylePrimitive `json:"definition_term,omitempty"`
DefinitionDescription StylePrimitive `json:"definition_description,omitempty"`
HTMLBlock StyleBlock `json:"html_block,omitempty"`
HTMLSpan StyleBlock `json:"html_span,omitempty"`
}
func cascadeStyles(toBlock bool, s ...StyleBlock) StyleBlock {
var r StyleBlock
for _, v := range s {
r = cascadeStyle(r, v, toBlock)
}
return r
}
func cascadeStyle(parent StyleBlock, child StyleBlock, toBlock bool) StyleBlock {
s := child
s.Color = parent.Color
s.BackgroundColor = parent.BackgroundColor
s.Underline = parent.Underline
s.Bold = parent.Bold
s.Italic = parent.Italic
s.CrossedOut = parent.CrossedOut
s.Faint = parent.Faint
s.Conceal = parent.Conceal
s.Overlined = parent.Overlined
s.Inverse = parent.Inverse
s.Blink = parent.Blink
if toBlock {
s.Indent = parent.Indent
s.Margin = parent.Margin
s.BlockPrefix = parent.BlockPrefix
s.BlockSuffix = parent.BlockSuffix
s.Prefix = parent.Prefix
s.Suffix = parent.Suffix
}
if child.Color != nil {
s.Color = child.Color
}
if child.BackgroundColor != nil {
s.BackgroundColor = child.BackgroundColor
}
if child.Indent != nil {
s.Indent = child.Indent
}
if child.Margin != nil {
s.Margin = child.Margin
}
if child.Underline != nil {
s.Underline = child.Underline
}
if child.Bold != nil {
s.Bold = child.Bold
}
if child.Italic != nil {
s.Italic = child.Italic
}
if child.CrossedOut != nil {
s.CrossedOut = child.CrossedOut
}
if child.Faint != nil {
s.Faint = child.Faint
}
if child.Conceal != nil {
s.Conceal = child.Conceal
}
if child.Overlined != nil {
s.Overlined = child.Overlined
}
if child.Inverse != nil {
s.Inverse = child.Inverse
}
if child.Blink != nil {
s.Blink = child.Blink
}
if child.BlockPrefix != "" {
s.BlockPrefix = child.BlockPrefix
}
if child.BlockSuffix != "" {
s.BlockSuffix = child.BlockSuffix
}
if child.Prefix != "" {
s.Prefix = child.Prefix
}
if child.Suffix != "" {
s.Suffix = child.Suffix
}
if child.Format != "" {
s.Format = child.Format
}
return s
}

View File

@@ -0,0 +1,33 @@
package ansi
import (
"bytes"
"io"
)
// StyleWriter is a Writer that applies styling on whatever you write to it.
type StyleWriter struct {
ctx RenderContext
w io.Writer
buf bytes.Buffer
rules StylePrimitive
}
// NewStyleWriter returns a new StyleWriter.
func NewStyleWriter(ctx RenderContext, w io.Writer, rules StylePrimitive) *StyleWriter {
return &StyleWriter{
ctx: ctx,
w: w,
rules: rules,
}
}
func (w *StyleWriter) Write(b []byte) (int, error) {
return w.buf.Write(b)
}
// Close must be called when you're finished writing to a StyleWriter.
func (w *StyleWriter) Close() error {
renderText(w.w, w.ctx.options.ColorProfile, w.rules, w.buf.String())
return nil
}

108
vendor/github.com/charmbracelet/glamour/ansi/table.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
package ansi
import (
"io"
"github.com/muesli/reflow/indent"
"github.com/olekukonko/tablewriter"
)
// A TableElement is used to render tables.
type TableElement struct {
writer *tablewriter.Table
styleWriter *StyleWriter
header []string
cell []string
}
// A TableRowElement is used to render a single row in a table.
type TableRowElement struct {
}
// A TableHeadElement is used to render a table's head element.
type TableHeadElement struct {
}
// A TableCellElement is used to render a single cell in a row.
type TableCellElement struct {
Text string
Head bool
}
func (e *TableElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack
var indentation uint
var margin uint
rules := ctx.options.Styles.Table
if rules.Indent != nil {
indentation = *rules.Indent
}
if rules.Margin != nil {
margin = *rules.Margin
}
iw := indent.NewWriterPipe(w, indentation+margin, func(wr io.Writer) {
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, " ")
})
style := bs.With(rules.StylePrimitive)
ctx.table.styleWriter = NewStyleWriter(ctx, iw, style)
renderText(w, ctx.options.ColorProfile, bs.Current().Style.StylePrimitive, rules.BlockPrefix)
renderText(ctx.table.styleWriter, ctx.options.ColorProfile, style, rules.Prefix)
ctx.table.writer = tablewriter.NewWriter(ctx.table.styleWriter)
return nil
}
func (e *TableElement) Finish(w io.Writer, ctx RenderContext) error {
rules := ctx.options.Styles.Table
ctx.table.writer.SetBorders(tablewriter.Border{Left: false, Top: false, Right: false, Bottom: false})
if rules.CenterSeparator != nil {
ctx.table.writer.SetCenterSeparator(*rules.CenterSeparator)
}
if rules.ColumnSeparator != nil {
ctx.table.writer.SetColumnSeparator(*rules.ColumnSeparator)
}
if rules.RowSeparator != nil {
ctx.table.writer.SetRowSeparator(*rules.RowSeparator)
}
ctx.table.writer.Render()
ctx.table.writer = nil
renderText(ctx.table.styleWriter, ctx.options.ColorProfile, ctx.blockStack.With(rules.StylePrimitive), rules.Suffix)
renderText(ctx.table.styleWriter, ctx.options.ColorProfile, ctx.blockStack.Current().Style.StylePrimitive, rules.BlockSuffix)
return ctx.table.styleWriter.Close()
}
func (e *TableRowElement) Finish(w io.Writer, ctx RenderContext) error {
if ctx.table.writer == nil {
return nil
}
ctx.table.writer.Append(ctx.table.cell)
ctx.table.cell = []string{}
return nil
}
func (e *TableHeadElement) Finish(w io.Writer, ctx RenderContext) error {
if ctx.table.writer == nil {
return nil
}
ctx.table.writer.SetHeader(ctx.table.header)
ctx.table.header = []string{}
return nil
}
func (e *TableCellElement) Render(w io.Writer, ctx RenderContext) error {
if e.Head {
ctx.table.header = append(ctx.table.header, e.Text)
} else {
ctx.table.cell = append(ctx.table.cell, e.Text)
}
return nil
}

26
vendor/github.com/charmbracelet/glamour/ansi/task.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package ansi
import (
"io"
)
// A TaskElement is used to render tasks inside a todo-list.
type TaskElement struct {
Checked bool
}
func (e *TaskElement) Render(w io.Writer, ctx RenderContext) error {
var el *BaseElement
pre := ctx.options.Styles.Task.Unticked
if e.Checked {
pre = ctx.options.Styles.Task.Ticked
}
el = &BaseElement{
Prefix: pre,
Style: ctx.options.Styles.Task.StylePrimitive,
}
return el.Render(w, ctx)
}

View File

@@ -0,0 +1,83 @@
package ansi
import (
"regexp"
"strings"
"text/template"
)
// TemplateFuncMap contains a few useful template helpers
var (
TemplateFuncMap = template.FuncMap{
"Left": func(values ...interface{}) string {
s := values[0].(string)
n := values[1].(int)
if n > len(s) {
n = len(s)
}
return s[:n]
},
"Matches": func(values ...interface{}) bool {
ok, _ := regexp.MatchString(values[1].(string), values[0].(string))
return ok
},
"Mid": func(values ...interface{}) string {
s := values[0].(string)
l := values[1].(int)
if l > len(s) {
l = len(s)
}
if len(values) > 2 {
r := values[2].(int)
if r > len(s) {
r = len(s)
}
return s[l:r]
}
return s[l:]
},
"Right": func(values ...interface{}) string {
s := values[0].(string)
n := len(s) - values[1].(int)
if n < 0 {
n = 0
}
return s[n:]
},
"Last": func(values ...interface{}) string {
return values[0].([]string)[len(values[0].([]string))-1]
},
// strings functions
"Compare": strings.Compare, // 1.5+ only
"Contains": strings.Contains,
"ContainsAny": strings.ContainsAny,
"Count": strings.Count,
"EqualFold": strings.EqualFold,
"HasPrefix": strings.HasPrefix,
"HasSuffix": strings.HasSuffix,
"Index": strings.Index,
"IndexAny": strings.IndexAny,
"Join": strings.Join,
"LastIndex": strings.LastIndex,
"LastIndexAny": strings.LastIndexAny,
"Repeat": strings.Repeat,
"Replace": strings.Replace,
"Split": strings.Split,
"SplitAfter": strings.SplitAfter,
"SplitAfterN": strings.SplitAfterN,
"SplitN": strings.SplitN,
"Title": strings.Title,
"ToLower": strings.ToLower,
"ToTitle": strings.ToTitle,
"ToUpper": strings.ToUpper,
"Trim": strings.Trim,
"TrimLeft": strings.TrimLeft,
"TrimPrefix": strings.TrimPrefix,
"TrimRight": strings.TrimRight,
"TrimSpace": strings.TrimSpace,
"TrimSuffix": strings.TrimSuffix,
}
)

19
vendor/github.com/charmbracelet/glamour/examples.sh generated vendored Normal file
View File

@@ -0,0 +1,19 @@
#!/bin/bash
set -e
for element in ./styles/examples/*.md; do
echo "Generating screenshot for element ${element}"
basename="`basename -s .md ${element}`"
stylename="${basename}.style"
filename="${basename}.png"
# take screenshot
./termshot -o ./styles/examples/ -f "$filename" glow -s ./styles/examples/${stylename} ${element}
# add border
convert -bordercolor black -border 16x16 "./styles/examples/$filename" "./styles/examples/$filename"
# optimize filesize
pngcrush -ow "./styles/examples/$filename"
done

20
vendor/github.com/charmbracelet/glamour/gallery.sh generated vendored Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
for style in ./styles/*.json; do
echo "Generating screenshot for ${style}"
filename="`basename -s .json ${style}`.png"
light=""
if [[ $style == *"light"* ]]; then
light="-l"
fi
# take screenshot
./termshot ${light} -o ./styles/gallery/ -f "$filename" glow -s ${style}
# add border
convert -bordercolor black -border 16x16 "./styles/gallery/$filename" "./styles/gallery/$filename"
# optimize filesize
pngcrush -ow "./styles/gallery/$filename"
done

245
vendor/github.com/charmbracelet/glamour/glamour.go generated vendored Normal file
View File

@@ -0,0 +1,245 @@
package glamour
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"github.com/muesli/termenv"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/util"
"github.com/charmbracelet/glamour/ansi"
)
// A TermRendererOption sets an option on a TermRenderer.
type TermRendererOption func(*TermRenderer) error
// TermRenderer can be used to render markdown content, posing a depth of
// customization and styles to fit your needs.
type TermRenderer struct {
md goldmark.Markdown
ansiOptions ansi.Options
buf bytes.Buffer
renderBuf bytes.Buffer
}
// Render initializes a new TermRenderer and renders a markdown with a specific
// style.
func Render(in string, stylePath string) (string, error) {
b, err := RenderBytes([]byte(in), stylePath)
return string(b), err
}
// RenderWithEnvironmentConfig initializes a new TermRenderer and renders a
// markdown with a specific style defined by the GLAMOUR_STYLE environment variable.
func RenderWithEnvironmentConfig(in string) (string, error) {
b, err := RenderBytes([]byte(in), getEnvironmentStyle())
return string(b), err
}
// RenderBytes initializes a new TermRenderer and renders a markdown with a
// specific style.
func RenderBytes(in []byte, stylePath string) ([]byte, error) {
r, err := NewTermRenderer(
WithStylePath(stylePath),
)
if err != nil {
return nil, err
}
return r.RenderBytes(in)
}
// NewTermRenderer returns a new TermRenderer the given options.
func NewTermRenderer(options ...TermRendererOption) (*TermRenderer, error) {
tr := &TermRenderer{
md: goldmark.New(
goldmark.WithExtensions(
extension.GFM,
extension.DefinitionList,
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
),
ansiOptions: ansi.Options{
WordWrap: 80,
ColorProfile: termenv.TrueColor,
},
}
for _, o := range options {
if err := o(tr); err != nil {
return nil, err
}
}
ar := ansi.NewRenderer(tr.ansiOptions)
tr.md.SetRenderer(
renderer.NewRenderer(
renderer.WithNodeRenderers(
util.Prioritized(ar, 1000),
),
),
)
return tr, nil
}
// WithBaseURL sets a TermRenderer's base URL.
func WithBaseURL(baseURL string) TermRendererOption {
return func(tr *TermRenderer) error {
tr.ansiOptions.BaseURL = baseURL
return nil
}
}
// WithColorProfile sets the TermRenderer's color profile
// (TrueColor / ANSI256 / ANSI).
func WithColorProfile(profile termenv.Profile) TermRendererOption {
return func(tr *TermRenderer) error {
tr.ansiOptions.ColorProfile = profile
return nil
}
}
// WithStandardStyle sets a TermRenderer's styles with a standard (builtin)
// style.
func WithStandardStyle(style string) TermRendererOption {
return func(tr *TermRenderer) error {
styles, err := getDefaultStyle(style)
if err != nil {
return err
}
tr.ansiOptions.Styles = *styles
return nil
}
}
// WithAutoStyle sets a TermRenderer's styles with either the standard dark
// or light style, depending on the terminal's background color at run-time.
func WithAutoStyle() TermRendererOption {
return WithStandardStyle("auto")
}
// WithEnvironmentConfig sets a TermRenderer's styles based on the
// GLAMOUR_STYLE environment variable.
func WithEnvironmentConfig() TermRendererOption {
return WithStylePath(getEnvironmentStyle())
}
// WithStylePath sets a TermRenderer's style from stylePath. stylePath is first
// interpreted as a filename. If no such file exists, it is re-interpreted as a
// standard style.
func WithStylePath(stylePath string) TermRendererOption {
return func(tr *TermRenderer) error {
jsonBytes, err := ioutil.ReadFile(stylePath)
switch {
case err == nil:
return json.Unmarshal(jsonBytes, &tr.ansiOptions.Styles)
case os.IsNotExist(err):
styles, err := getDefaultStyle(stylePath)
if err != nil {
return err
}
tr.ansiOptions.Styles = *styles
return nil
default:
return err
}
}
}
// WithStyles sets a TermRenderer's styles.
func WithStyles(styles ansi.StyleConfig) TermRendererOption {
return func(tr *TermRenderer) error {
tr.ansiOptions.Styles = styles
return nil
}
}
// WithStylesFromJSONBytes sets a TermRenderer's styles by parsing styles from
// jsonBytes.
func WithStylesFromJSONBytes(jsonBytes []byte) TermRendererOption {
return func(tr *TermRenderer) error {
return json.Unmarshal(jsonBytes, &tr.ansiOptions.Styles)
}
}
// WithStylesFromJSONFile sets a TermRenderer's styles from a JSON file.
func WithStylesFromJSONFile(filename string) TermRendererOption {
return func(tr *TermRenderer) error {
jsonBytes, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return json.Unmarshal(jsonBytes, &tr.ansiOptions.Styles)
}
}
// WithWordWrap sets a TermRenderer's word wrap.
func WithWordWrap(wordWrap int) TermRendererOption {
return func(tr *TermRenderer) error {
tr.ansiOptions.WordWrap = wordWrap
return nil
}
}
func (tr *TermRenderer) Read(b []byte) (int, error) {
return tr.renderBuf.Read(b)
}
func (tr *TermRenderer) Write(b []byte) (int, error) {
return tr.buf.Write(b)
}
// Close must be called after writing to TermRenderer. You can then retrieve
// the rendered markdown by calling Read.
func (tr *TermRenderer) Close() error {
err := tr.md.Convert(tr.buf.Bytes(), &tr.renderBuf)
if err != nil {
return err
}
tr.buf.Reset()
return nil
}
// Render returns the markdown rendered into a string.
func (tr *TermRenderer) Render(in string) (string, error) {
b, err := tr.RenderBytes([]byte(in))
return string(b), err
}
// RenderBytes returns the markdown rendered into a byte slice.
func (tr *TermRenderer) RenderBytes(in []byte) ([]byte, error) {
var buf bytes.Buffer
err := tr.md.Convert(in, &buf)
return buf.Bytes(), err
}
func getEnvironmentStyle() string {
glamourStyle := os.Getenv("GLAMOUR_STYLE")
if len(glamourStyle) == 0 {
glamourStyle = "auto"
}
return glamourStyle
}
func getDefaultStyle(style string) (*ansi.StyleConfig, error) {
if style == "auto" {
if termenv.HasDarkBackground() {
return &DarkStyleConfig, nil
}
return &LightStyleConfig, nil
}
styles, ok := DefaultStyles[style]
if !ok {
return nil, fmt.Errorf("%s: style not found", style)
}
return styles, nil
}

12
vendor/github.com/charmbracelet/glamour/go.mod generated vendored Normal file
View File

@@ -0,0 +1,12 @@
module github.com/charmbracelet/glamour
go 1.13
require (
github.com/alecthomas/chroma v0.7.3
github.com/microcosm-cc/bluemonday v1.0.2
github.com/muesli/reflow v0.1.0
github.com/muesli/termenv v0.6.0
github.com/olekukonko/tablewriter v0.0.4
github.com/yuin/goldmark v1.2.0
)

54
vendor/github.com/charmbracelet/glamour/go.sum generated vendored Normal file
View File

@@ -0,0 +1,54 @@
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.7.3 h1:NfdAERMy+esYQs8OXk0I868/qDxxCEo7FMz1WIqMAeI=
github.com/alecthomas/chroma v0.7.3/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/muesli/reflow v0.1.0 h1:oQdpLfO56lr5pgLvqD0TcjW85rDjSYSBVdiG1Ch1ddM=
github.com/muesli/reflow v0.1.0/go.mod h1:I9bWAt7QTg/que/qmUCJBGlj7wEq8OAFBjPNjc6xK4I=
github.com/muesli/termenv v0.6.0 h1:zxvzTBmo4ZcxhNGGWeMz+Tttm51eF5bmPjfy4MCRYlk=
github.com/muesli/termenv v0.6.0/go.mod h1:SohX91w6swWA4AYU+QmPx+aSgXhWO0juiyID9UZmbpA=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/yuin/goldmark v1.2.0 h1:WOOcyaJPlzb8fZ8TloxFe8QZkhOOJx87leDa9MIT9dc=
github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

660
vendor/github.com/charmbracelet/glamour/styles.go generated vendored Normal file
View File

@@ -0,0 +1,660 @@
package glamour
//go:generate go run ./internal/generate-style-json
import (
"github.com/charmbracelet/glamour/ansi"
)
var (
// ASCIIStyleConfig uses only ASCII characters.
ASCIIStyleConfig = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "\n",
BlockSuffix: "\n",
},
Margin: uintPtr(2),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: uintPtr(1),
IndentToken: stringPtr("| "),
},
Paragraph: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
List: ansi.StyleList{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
LevelIndent: 4,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "# ",
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
},
},
Strikethrough: ansi.StylePrimitive{
BlockPrefix: "~~",
BlockSuffix: "~~",
},
Emph: ansi.StylePrimitive{
BlockPrefix: "*",
BlockSuffix: "*",
},
Strong: ansi.StylePrimitive{
BlockPrefix: "**",
BlockSuffix: "**",
},
HorizontalRule: ansi.StylePrimitive{
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
Ticked: "[x] ",
Unticked: "[ ] ",
},
ImageText: ansi.StylePrimitive{
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "`",
BlockSuffix: "`",
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
Margin: uintPtr(2),
},
},
Table: ansi.StyleTable{
CenterSeparator: stringPtr("+"),
ColumnSeparator: stringPtr("|"),
RowSeparator: stringPtr("-"),
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n* ",
},
}
// DarkStyleConfig is the default dark style.
DarkStyleConfig = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "\n",
BlockSuffix: "\n",
Color: stringPtr("252"),
},
Margin: uintPtr(2),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: uintPtr(1),
IndentToken: stringPtr("│ "),
},
List: ansi.StyleList{
LevelIndent: 2,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Color: stringPtr("39"),
Bold: boolPtr(true),
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: stringPtr("228"),
BackgroundColor: stringPtr("63"),
Bold: boolPtr(true),
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Color: stringPtr("35"),
Bold: boolPtr(false),
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: boolPtr(true),
},
Emph: ansi.StylePrimitive{
Italic: boolPtr(true),
},
Strong: ansi.StylePrimitive{
Bold: boolPtr(true),
},
HorizontalRule: ansi.StylePrimitive{
Color: stringPtr("240"),
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Color: stringPtr("30"),
Underline: boolPtr(true),
},
LinkText: ansi.StylePrimitive{
Color: stringPtr("35"),
Bold: boolPtr(true),
},
Image: ansi.StylePrimitive{
Color: stringPtr("212"),
Underline: boolPtr(true),
},
ImageText: ansi.StylePrimitive{
Color: stringPtr("243"),
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: stringPtr("203"),
BackgroundColor: stringPtr("236"),
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: stringPtr("244"),
},
Margin: uintPtr(2),
},
Chroma: &ansi.Chroma{
Text: ansi.StylePrimitive{
Color: stringPtr("#C4C4C4"),
},
Error: ansi.StylePrimitive{
Color: stringPtr("#F1F1F1"),
BackgroundColor: stringPtr("#F05B5B"),
},
Comment: ansi.StylePrimitive{
Color: stringPtr("#676767"),
},
CommentPreproc: ansi.StylePrimitive{
Color: stringPtr("#FF875F"),
},
Keyword: ansi.StylePrimitive{
Color: stringPtr("#00AAFF"),
},
KeywordReserved: ansi.StylePrimitive{
Color: stringPtr("#FF5FD2"),
},
KeywordNamespace: ansi.StylePrimitive{
Color: stringPtr("#FF5F87"),
},
KeywordType: ansi.StylePrimitive{
Color: stringPtr("#6E6ED8"),
},
Operator: ansi.StylePrimitive{
Color: stringPtr("#EF8080"),
},
Punctuation: ansi.StylePrimitive{
Color: stringPtr("#E8E8A8"),
},
Name: ansi.StylePrimitive{
Color: stringPtr("#C4C4C4"),
},
NameBuiltin: ansi.StylePrimitive{
Color: stringPtr("#FF8EC7"),
},
NameTag: ansi.StylePrimitive{
Color: stringPtr("#B083EA"),
},
NameAttribute: ansi.StylePrimitive{
Color: stringPtr("#7A7AE6"),
},
NameClass: ansi.StylePrimitive{
Color: stringPtr("#F1F1F1"),
Underline: boolPtr(true),
Bold: boolPtr(true),
},
NameDecorator: ansi.StylePrimitive{
Color: stringPtr("#FFFF87"),
},
NameFunction: ansi.StylePrimitive{
Color: stringPtr("#00D787"),
},
LiteralNumber: ansi.StylePrimitive{
Color: stringPtr("#6EEFC0"),
},
LiteralString: ansi.StylePrimitive{
Color: stringPtr("#C69669"),
},
LiteralStringEscape: ansi.StylePrimitive{
Color: stringPtr("#AFFFD7"),
},
GenericDeleted: ansi.StylePrimitive{
Color: stringPtr("#FD5B5B"),
},
GenericEmph: ansi.StylePrimitive{
Italic: boolPtr(true),
},
GenericInserted: ansi.StylePrimitive{
Color: stringPtr("#00D787"),
},
GenericStrong: ansi.StylePrimitive{
Bold: boolPtr(true),
},
GenericSubheading: ansi.StylePrimitive{
Color: stringPtr("#777777"),
},
Background: ansi.StylePrimitive{
BackgroundColor: stringPtr("#373737"),
},
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
CenterSeparator: stringPtr("┼"),
ColumnSeparator: stringPtr("│"),
RowSeparator: stringPtr("─"),
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n🠶 ",
},
}
// LightStyleConfig is the default light style.
LightStyleConfig = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "\n",
BlockSuffix: "\n",
Color: stringPtr("234"),
},
Margin: uintPtr(2),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: uintPtr(1),
IndentToken: stringPtr("│ "),
},
List: ansi.StyleList{
LevelIndent: 2,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
Color: stringPtr("27"),
Bold: boolPtr(true),
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: stringPtr("228"),
BackgroundColor: stringPtr("63"),
Bold: boolPtr(true),
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
Bold: boolPtr(false),
},
},
Strikethrough: ansi.StylePrimitive{
CrossedOut: boolPtr(true),
},
Emph: ansi.StylePrimitive{
Italic: boolPtr(true),
},
Strong: ansi.StylePrimitive{
Bold: boolPtr(true),
},
HorizontalRule: ansi.StylePrimitive{
Color: stringPtr("249"),
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
StylePrimitive: ansi.StylePrimitive{},
Ticked: "[✓] ",
Unticked: "[ ] ",
},
Link: ansi.StylePrimitive{
Color: stringPtr("36"),
Underline: boolPtr(true),
},
LinkText: ansi.StylePrimitive{
Color: stringPtr("29"),
Bold: boolPtr(true),
},
Image: ansi.StylePrimitive{
Color: stringPtr("205"),
Underline: boolPtr(true),
},
ImageText: ansi.StylePrimitive{
Color: stringPtr("243"),
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: " ",
Suffix: " ",
Color: stringPtr("203"),
BackgroundColor: stringPtr("254"),
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Color: stringPtr("242"),
},
Margin: uintPtr(2),
},
Chroma: &ansi.Chroma{
Text: ansi.StylePrimitive{
Color: stringPtr("#2A2A2A"),
},
Error: ansi.StylePrimitive{
Color: stringPtr("#F1F1F1"),
BackgroundColor: stringPtr("#FF5555"),
},
Comment: ansi.StylePrimitive{
Color: stringPtr("#8D8D8D"),
},
CommentPreproc: ansi.StylePrimitive{
Color: stringPtr("#FF875F"),
},
Keyword: ansi.StylePrimitive{
Color: stringPtr("#279EFC"),
},
KeywordReserved: ansi.StylePrimitive{
Color: stringPtr("#FF5FD2"),
},
KeywordNamespace: ansi.StylePrimitive{
Color: stringPtr("#FB406F"),
},
KeywordType: ansi.StylePrimitive{
Color: stringPtr("#7049C2"),
},
Operator: ansi.StylePrimitive{
Color: stringPtr("#FF2626"),
},
Punctuation: ansi.StylePrimitive{
Color: stringPtr("#FA7878"),
},
NameBuiltin: ansi.StylePrimitive{
Color: stringPtr("#0A1BB1"),
},
NameTag: ansi.StylePrimitive{
Color: stringPtr("#581290"),
},
NameAttribute: ansi.StylePrimitive{
Color: stringPtr("#8362CB"),
},
NameClass: ansi.StylePrimitive{
Color: stringPtr("#212121"),
Underline: boolPtr(true),
Bold: boolPtr(true),
},
NameConstant: ansi.StylePrimitive{
Color: stringPtr("#581290"),
},
NameDecorator: ansi.StylePrimitive{
Color: stringPtr("#A3A322"),
},
NameFunction: ansi.StylePrimitive{
Color: stringPtr("#019F57"),
},
LiteralNumber: ansi.StylePrimitive{
Color: stringPtr("#22CCAE"),
},
LiteralString: ansi.StylePrimitive{
Color: stringPtr("#7E5B38"),
},
LiteralStringEscape: ansi.StylePrimitive{
Color: stringPtr("#00AEAE"),
},
GenericDeleted: ansi.StylePrimitive{
Color: stringPtr("#FD5B5B"),
},
GenericEmph: ansi.StylePrimitive{
Italic: boolPtr(true),
},
GenericInserted: ansi.StylePrimitive{
Color: stringPtr("#00D787"),
},
GenericStrong: ansi.StylePrimitive{
Bold: boolPtr(true),
},
GenericSubheading: ansi.StylePrimitive{
Color: stringPtr("#777777"),
},
Background: ansi.StylePrimitive{
BackgroundColor: stringPtr("#373737"),
},
},
},
Table: ansi.StyleTable{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
CenterSeparator: stringPtr("┼"),
ColumnSeparator: stringPtr("│"),
RowSeparator: stringPtr("─"),
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n🠶 ",
},
}
// NoTTYStyleConfig is the default notty style.
NoTTYStyleConfig = ansi.StyleConfig{
Document: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "\n",
BlockSuffix: "\n",
},
Margin: uintPtr(2),
},
BlockQuote: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
Indent: uintPtr(1),
IndentToken: stringPtr("│ "),
},
Paragraph: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
List: ansi.StyleList{
StyleBlock: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{},
},
LevelIndent: 4,
},
Heading: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockSuffix: "\n",
},
},
H1: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "# ",
},
},
H2: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "## ",
},
},
H3: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "### ",
},
},
H4: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "#### ",
},
},
H5: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "##### ",
},
},
H6: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
Prefix: "###### ",
},
},
Strikethrough: ansi.StylePrimitive{
BlockPrefix: "~~",
BlockSuffix: "~~",
},
Emph: ansi.StylePrimitive{
BlockPrefix: "*",
BlockSuffix: "*",
},
Strong: ansi.StylePrimitive{
BlockPrefix: "**",
BlockSuffix: "**",
},
HorizontalRule: ansi.StylePrimitive{
Format: "\n--------\n",
},
Item: ansi.StylePrimitive{
BlockPrefix: "• ",
},
Enumeration: ansi.StylePrimitive{
BlockPrefix: ". ",
},
Task: ansi.StyleTask{
Ticked: "[✓] ",
Unticked: "[ ] ",
},
ImageText: ansi.StylePrimitive{
Format: "Image: {{.text}} →",
},
Code: ansi.StyleBlock{
StylePrimitive: ansi.StylePrimitive{
BlockPrefix: "`",
BlockSuffix: "`",
},
},
CodeBlock: ansi.StyleCodeBlock{
StyleBlock: ansi.StyleBlock{
Margin: uintPtr(2),
},
},
Table: ansi.StyleTable{
CenterSeparator: stringPtr("┼"),
ColumnSeparator: stringPtr("│"),
RowSeparator: stringPtr("─"),
},
DefinitionDescription: ansi.StylePrimitive{
BlockPrefix: "\n🠶 ",
},
}
// DefaultStyles are the default styles.
DefaultStyles = map[string]*ansi.StyleConfig{
"ascii": &ASCIIStyleConfig,
"dark": &DarkStyleConfig,
"light": &LightStyleConfig,
"notty": &NoTTYStyleConfig,
}
)
func boolPtr(b bool) *bool { return &b }
func stringPtr(s string) *string { return &s }
func uintPtr(u uint) *uint { return &u }