1package common
 2
 3import (
 4	"fmt"
 5	"strings"
 6
 7	"github.com/alecthomas/chroma/v2/lexers"
 8	gansi "github.com/charmbracelet/glamour/ansi"
 9	"github.com/charmbracelet/soft-serve/pkg/ui/styles"
10)
11
12// FormatLineNumber adds line numbers to a string.
13func FormatLineNumber(styles *styles.Styles, s string, color bool) (string, int) {
14	lines := strings.Split(s, "\n")
15	// NB: len() is not a particularly safe way to count string width (because
16	// it's counting bytes instead of runes) but in this case it's okay
17	// because we're only dealing with digits, which are one byte each.
18	mll := len(fmt.Sprintf("%d", len(lines)))
19	for i, l := range lines {
20		digit := fmt.Sprintf("%*d", mll, i+1)
21		bar := "│"
22		if color {
23			digit = styles.Code.LineDigit.Render(digit)
24			bar = styles.Code.LineBar.Render(bar)
25		}
26		if i < len(lines)-1 || len(l) != 0 {
27			// If the final line was a newline we'll get an empty string for
28			// the final line, so drop the newline altogether.
29			lines[i] = fmt.Sprintf(" %s %s %s", digit, bar, l)
30		}
31	}
32	return strings.Join(lines, "\n"), mll
33}
34
35// FormatHighlight adds syntax highlighting to a string.
36func FormatHighlight(p, c string) (string, error) {
37	zero := uint(0)
38	lang := ""
39	lexer := lexers.Match(p)
40	if lexer != nil && lexer.Config() != nil {
41		lang = lexer.Config().Name
42	}
43	formatter := &gansi.CodeBlockElement{
44		Code:     c,
45		Language: lang,
46	}
47	r := strings.Builder{}
48	styles := StyleConfig()
49	styles.CodeBlock.Margin = &zero
50	rctx := StyleRendererWithStyles(styles)
51	err := formatter.Render(&r, rctx)
52	if err != nil {
53		return "", err
54	}
55	return r.String(), nil
56}