package tldr
import (
"errors"
"git.sophuwu.com/manweb/CFG"
"git.sophuwu.com/manweb/embeds"
"git.sophuwu.com/manweb/logs"
"git.sophuwu.com/manweb/neterr"
"git.sophuwu.com/manweb/stats"
"net/http"
"os"
"strings"
"time"
"os/exec"
"path/filepath"
)
func GitDir() string { return filepath.Join(CFG.TldrDir, "tldr.git") }
var TldrPagesMap = make(map[string]string)
func Open() {
if !CFG.TldrPages {
return
}
_ = os.MkdirAll(CFG.TldrDir, 0755)
var cmd *exec.Cmd
st, err := os.Stat(GitDir())
if err != nil && os.IsNotExist(err) {
cmd = exec.Command("/bin/git", "clone", "--bare", CFG.TldrGitSrc, GitDir())
} else if err != nil {
logs.CheckFatal("unable to access tldr pages repository", err)
} else if !st.IsDir() {
logs.Fatalf("tldr pages repository is not a directory: %s", GitDir())
} else if st.ModTime().Before(time.Now().AddDate(0, 0, -14)) {
cmd = exec.Command("/bin/git", "--git-dir", GitDir(), "fetch", "--all")
}
if cmd != nil {
cmd.Dir = CFG.TldrDir
err = cmd.Run()
logs.CheckFatal("unable to clone tldr pages repository", err)
}
TldrPagesMap = make(map[string]string)
fn := func(path string) {
cmd = exec.Command("/bin/git", "--no-pager", "--git-dir", GitDir(), "ls-tree", "--name-only", "main:pages/"+path)
cmd.Dir = CFG.TldrDir
var b []byte
b, err = cmd.Output()
logs.CheckFatal("unable to list tldr pages", err)
for _, line := range strings.Split(string(b), "\n") {
line = strings.TrimSpace(line)
if len(line) == 0 || !strings.HasSuffix(line, ".md") {
continue
}
name := strings.TrimSuffix(line, ".md")
TldrPagesMap[name] = filepath.Join(path, line)
}
}
fn("common")
fn("linux")
}
type TldrPage struct {
Name string
Path string
Content string
}
func (p *TldrPage) findPath() error {
if p.Name == "" {
return errors.New("tldr page name cannot be empty")
}
var ok bool
p.Path, ok = TldrPagesMap[p.Name]
if !ok {
return errors.New("tldr page not found: " + p.Name)
}
return nil
}
func (p *TldrPage) open() error {
err := p.findPath()
if err != nil {
return err
}
cmd := exec.Command("/bin/git", "--git-dir", GitDir(), "show", "main:pages/"+p.Path)
cmd.Dir = CFG.TldrDir
b, err := cmd.Output()
if err != nil {
return err
}
if len(b) == 0 {
return errors.New("Page not found: " + p.Name)
}
p.Content = strings.TrimSpace(string(b))
return nil
}
/*
tldr page format:
# tldr page name
> tldr page description
- command 1
`command 1 usage`
- command 2
`command 2 usage`
Specification:
lines beginning with `#` are titles
lines beginning with `>` are descriptions
inline urls, inside <> tags
may contain inline code
lines beginning with `-` list elements
may contain inline code
`codeblocks` on same level
*/
func inlineLink(s string) string {
i := strings.Index(s, "<")
if i < 0 {
return s
}
j := strings.Index(s[i:], ">")
if j < 0 {
return s
}
j += i
return s[:i] + `` + s[i+1:j] + `` + inlineLink(s[j+1:])
}
func inlineCode(s string) string {
i := strings.Index(s, "`")
if i < 0 {
return s
}
j := strings.Index(s[i+1:], "`")
if j < 0 {
return s
}
j += i + 1
return s[:i] + `` + s[i+1:j] + `
` + inlineCode(s[j+1:])
}
func inline(s string) string {
s = inlineLink(s)
s = inlineCode(s)
return s
}
func htmlEscape(s string) string {
s = strings.ReplaceAll(s, "&", "&")
s = strings.ReplaceAll(s, "<", "<")
s = strings.ReplaceAll(s, ">", ">")
s = strings.ReplaceAll(s, `"`, """)
s = strings.ReplaceAll(s, "'", "'")
return s
}
func (p *TldrPage) HTML() (string, error) {
s := ""
lines := strings.Split(p.Content, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
i := strings.Index(line, " ")
if strings.HasPrefix(line, "#") {
if i < 0 {
return "", errors.New("invalid tldr page format: missing space after title")
}
s += `
` + inline(htmlEscape(line[i+1:])) + "
\n" } else if strings.HasPrefix(line, "-") { if i < 0 { return "", errors.New("invalid tldr page format: missing space after list item") } s += `` + inline(htmlEscape(line[i+1:])) + "
\n" } else if strings.HasPrefix(line, "`") && strings.HasSuffix(line, "`") { s += `` + htmlEscape(line[1:len(line)-1]) + "\n" } else { s += `
` + inline(htmlEscape(line)) + "
\n" } } if len(s) == 0 { return "", errors.New("invalid tldr page format: no content found") } s = `