1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
// Package utils provides utility functions.
package utils
import (
"os"
"path/filepath"
"regexp"
"strings"
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/glamour/ansi"
"github.com/charmbracelet/glamour/styles"
"github.com/charmbracelet/lipgloss"
"github.com/mitchellh/go-homedir"
)
// RemoveFrontmatter removes the front matter header of a markdown file.
func RemoveFrontmatter(content []byte) []byte {
if frontmatterBoundaries := detectFrontmatter(content); frontmatterBoundaries[0] == 0 {
return content[frontmatterBoundaries[1]:]
}
return content
}
var yamlPattern = regexp.MustCompile(`(?m)^---\r?\n(\s*\r?\n)?`)
func detectFrontmatter(c []byte) []int {
if matches := yamlPattern.FindAllIndex(c, 2); len(matches) > 1 {
return []int{matches[0][0], matches[1][1]}
}
return []int{-1, -1}
}
// ExpandPath expands tilde and all environment variables from the given path.
func ExpandPath(path string) string {
s, err := homedir.Expand(path)
if err == nil {
return os.ExpandEnv(s)
}
return os.ExpandEnv(path)
}
// WrapCodeBlock wraps a string in a code block with the given language.
func WrapCodeBlock(s, language string) string {
return "```" + language + "\n" + s + "```"
}
var markdownExtensions = []string{
".md", ".mdown", ".mkdn", ".mkd", ".markdown",
}
// IsMarkdownFile returns whether the filename has a markdown extension.
func IsMarkdownFile(filename string) bool {
ext := filepath.Ext(filename)
if ext == "" {
// By default, assume it's a markdown file.
return true
}
for _, v := range markdownExtensions {
if strings.EqualFold(ext, v) {
return true
}
}
// Has an extension but not markdown
// so assume this is a code file.
return false
}
// GlamourStyle returns a glamour.TermRendererOption based on the given style.
func GlamourStyle(style string, isCode bool) glamour.TermRendererOption {
if !isCode {
if style == styles.AutoStyle {
return glamour.WithAutoStyle()
}
return glamour.WithStylePath(style)
}
// If we are rendering a pure code block, we need to modify the style to
// remove the indentation.
var styleConfig ansi.StyleConfig
switch style {
case styles.AutoStyle:
if lipgloss.HasDarkBackground() {
styleConfig = styles.DarkStyleConfig
} else {
styleConfig = styles.LightStyleConfig
}
case styles.DarkStyle:
styleConfig = styles.DarkStyleConfig
case styles.LightStyle:
styleConfig = styles.LightStyleConfig
case styles.PinkStyle:
styleConfig = styles.PinkStyleConfig
case styles.NoTTYStyle:
styleConfig = styles.NoTTYStyleConfig
case styles.DraculaStyle:
styleConfig = styles.DraculaStyleConfig
case styles.TokyoNightStyle:
styleConfig = styles.DraculaStyleConfig
default:
return glamour.WithStylesFromJSONFile(style)
}
var margin uint
styleConfig.CodeBlock.Margin = &margin
return glamour.WithStyles(styleConfig)
}
|