GitRoot

Craft your forge, Build your project, Grow your community freely
 1// SPDX-FileCopyrightText: 2026 Romain Maneschi <romain@gitroot.dev>
 2//
 3// SPDX-License-Identifier: EUPL-1.2
 4
 5package main
 6
 7import (
 8	"bytes"
 9	"fmt"
10	"io/fs"
11	"regexp"
12	"strings"
13
14	"gitroot.dev/libs/golang/plugin/model"
15)
16
17type rendererEmbed struct {
18	conf   Conf
19	server model.Server
20}
21
22func NewRendererEmbed(conf Conf, server model.Server) rendererEmbed {
23	return rendererEmbed{conf: conf, server: server}
24}
25
26func (r rendererEmbed) renderPage(pageBuilder *strings.Builder, lines []CacheLineRelativeLink) {
27	for i, line := range lines {
28		pageBuilder.WriteString(r.makeLink(line.line, line.relativePath))
29		if i < len(lines)-1 {
30			pageBuilder.WriteString("\n")
31		}
32	}
33}
34
35func (r rendererEmbed) makeLink(cacheLine CacheLine, path string) string {
36	t := cacheLine.selects
37	append := "\n\n"
38	for i, a := range t {
39		if i == 0 {
40			append = fmt.Sprintf("%s%s", append, a)
41		}
42	}
43	append = fmt.Sprintf("%s\n%s\n", append, r.findEmbed(cacheLine.fp))
44	return fmt.Sprintf("### [%s](%s)%s", cacheLine.title, path, append)
45}
46
47func (r rendererEmbed) findEmbed(path string) string {
48	content, err := fs.ReadFile(r.server.Worktree(), path)
49	if err != nil {
50		r.server.LogError("can't find file", err)
51		return ""
52	}
53	if strings.HasSuffix(path, ".md") { //special case, search first description
54		re := regexp.MustCompile(`(?m)^#\s(.*)$`)
55		t := re.FindSubmatch(content)
56		hasTitle := len(t) > 1
57		hasMeta := bytes.Contains(content, []byte("---"))
58		contents := bytes.Split(content, []byte("\n"))
59		for i, l := range contents {
60			titleCase := hasTitle && bytes.HasPrefix(l, []byte("# "))
61			metaCase := !hasTitle && hasMeta && i > 0 && bytes.HasPrefix(l, []byte("---"))
62			bodyCase := !hasTitle && !hasMeta
63			if titleCase || metaCase || bodyCase {
64				res := ""
65				if i+1 < len(contents) && len(contents[i+1]) > 0 {
66					res = fmt.Sprintf("%s\n%s", res, string(contents[i+1]))
67				}
68				if i+2 < len(contents) && len(contents[i+2]) > 0 {
69					res = fmt.Sprintf("%s\n%s", res, string(contents[i+2]))
70				}
71				if i+3 < len(contents) && len(contents[i+3]) > 0 {
72					res = fmt.Sprintf("%s\n%s", res, string(contents[i+3]))
73				}
74				return res
75			}
76		}
77	} else {
78		contents := bytes.Split(content, []byte("\n"))
79		for i, l := range contents {
80			if bytes.Contains(l, []byte(r.conf.Where)) {
81				var buffer bytes.Buffer
82				buffer.Write([]byte("```\n"))
83				if i > 0 {
84					buffer.Write(contents[i-1])
85					buffer.Write([]byte("\n"))
86				}
87				buffer.Write(l)
88				if i < len(contents) {
89					buffer.Write([]byte("\n"))
90					buffer.Write(contents[i+1])
91				}
92				buffer.Write([]byte("\n```"))
93				return buffer.String()
94			}
95		}
96	}
97
98	return "-"
99}