Skip to content

Commit 21c668b

Browse files
committed
docs: render markdown documentation [wip]
1 parent 0f9217b commit 21c668b

File tree

5 files changed

+166
-10
lines changed

5 files changed

+166
-10
lines changed

docs/docs.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package docs
2+
3+
import (
4+
"bytes"
5+
"embed"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"strings"
10+
11+
"github.com/Depado/bfchroma/v2"
12+
"github.com/alecthomas/chroma/v2/formatters/html"
13+
bf "github.com/russross/blackfriday/v2"
14+
"gopkg.in/yaml.v3"
15+
)
16+
17+
//go:embed docs.yml *.md **/*.md
18+
var sources embed.FS
19+
20+
type page struct {
21+
Title string
22+
Breadcrumbs []string
23+
Body string
24+
File string
25+
Route string
26+
Children []*page
27+
}
28+
29+
var root = func() page {
30+
structure, err := sources.Open("docs.yml")
31+
if err != nil {
32+
panic(err)
33+
}
34+
defer structure.Close()
35+
36+
var menu page
37+
dec := yaml.NewDecoder(structure)
38+
dec.KnownFields(true)
39+
if err := dec.Decode(&menu); err != nil {
40+
panic(err)
41+
}
42+
43+
menu.init()
44+
return menu
45+
}()
46+
47+
func (pg *page) init(crumbs ...string) {
48+
if pg.File != "" {
49+
if r := strings.TrimSuffix(pg.File, ".md"); r == "index" {
50+
pg.Route = ""
51+
} else {
52+
pg.Route = "/" + r
53+
}
54+
55+
pg.parseFile()
56+
}
57+
if pg.Title != "" {
58+
pg.Breadcrumbs = append(pg.Breadcrumbs, pg.Title)
59+
}
60+
for _, child := range pg.Children {
61+
child.init(pg.Breadcrumbs...)
62+
}
63+
}
64+
65+
func (pg *page) parseFile() {
66+
body, err := sources.ReadFile(pg.File)
67+
if err != nil {
68+
panic(err)
69+
}
70+
71+
r := bfchroma.NewRenderer(
72+
bfchroma.WithoutAutodetect(),
73+
bfchroma.ChromaOptions(
74+
html.WithLineNumbers(true),
75+
),
76+
bfchroma.Extend(bf.NewHTMLRenderer(bf.HTMLRendererParameters{
77+
Flags: bf.CommonHTMLFlags & ^bf.UseXHTML & ^bf.CompletePage,
78+
})),
79+
)
80+
parser := bf.New(
81+
bf.WithExtensions(bf.CommonExtensions),
82+
bf.WithRenderer(r),
83+
)
84+
85+
ast := parser.Parse(body)
86+
var buf bytes.Buffer
87+
var inH1 bool
88+
89+
ast.Walk(func(node *bf.Node, entering bool) bf.WalkStatus {
90+
switch node.Type {
91+
case bf.Heading:
92+
inH1 = entering && node.HeadingData.Level == 1 && pg.Title == ""
93+
case bf.Text:
94+
if inH1 {
95+
pg.Title = string(node.Literal)
96+
}
97+
case bf.Link:
98+
if entering && bytes.HasPrefix(node.LinkData.Destination, []byte("./")) {
99+
node.LinkData.Destination = bytes.TrimSuffix(node.LinkData.Destination, []byte(".md"))
100+
}
101+
}
102+
return r.RenderNode(&buf, node, entering)
103+
})
104+
105+
pg.Body = buf.String()
106+
}
107+
108+
func (pg *page) Dump(w io.Writer) {
109+
fmt.Fprintf(w, "- %s (%s)\n", pg.Title, pg.Route)
110+
fmt.Fprintln(w, pg.Body)
111+
fmt.Fprintln(w)
112+
113+
for _, c := range pg.Children {
114+
c.Dump(w)
115+
}
116+
}
117+
118+
func Handler() http.Handler {
119+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
120+
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
121+
w.Header().Set("X-Content-Type-Options", "nosniff")
122+
w.WriteHeader(http.StatusOK)
123+
124+
fmt.Fprintf(w, "%#v\n\n", r.URL)
125+
126+
root.Dump(w)
127+
})
128+
}

docs/docs.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
file: index.md
3+
children:
4+
- file: operation-modes.md
5+
- file: cli-options.md
6+
- title: HTTP API
7+
children:
8+
- file: http-api/render.md
9+
- file: http-api/status.md
10+
- file: http-api/metrics.md
11+
- file: http-api/web-ui.md
12+
- file: reference-store.md
13+
- file: history.md
14+
- file: future.md

go.mod

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module github.com/digineo/texd
33
go 1.18
44

55
require (
6+
github.com/Depado/bfchroma/v2 v2.0.0
7+
github.com/alecthomas/chroma/v2 v2.2.0
68
github.com/bahlo/generic-list-go v0.2.0
79
github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d
810
github.com/docker/docker v20.10.17+incompatible
@@ -12,11 +14,13 @@ require (
1214
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
1315
github.com/opencontainers/image-spec v1.0.2
1416
github.com/prometheus/client_golang v1.12.2
17+
github.com/russross/blackfriday/v2 v2.1.0
1518
github.com/spf13/afero v1.8.2
1619
github.com/spf13/pflag v1.0.5
1720
github.com/stretchr/testify v1.8.0
1821
github.com/thediveo/enumflag v0.10.1
1922
go.uber.org/zap v1.21.0
23+
gopkg.in/yaml.v3 v3.0.1
2024
)
2125

2226
require (
@@ -25,6 +29,7 @@ require (
2529
github.com/beorn7/perks v1.0.1 // indirect
2630
github.com/cespare/xxhash/v2 v2.1.2 // indirect
2731
github.com/davecgh/go-spew v1.1.1 // indirect
32+
github.com/dlclark/regexp2 v1.4.0 // indirect
2833
github.com/docker/distribution v2.8.1+incompatible // indirect
2934
github.com/docker/go-connections v0.4.0 // indirect
3035
github.com/felixge/httpsnoop v1.0.3 // indirect
@@ -40,21 +45,20 @@ require (
4045
github.com/pkg/errors v0.9.1 // indirect
4146
github.com/pmezard/go-difflib v1.0.0 // indirect
4247
github.com/prometheus/client_model v0.2.0 // indirect
43-
github.com/prometheus/common v0.34.0 // indirect
48+
github.com/prometheus/common v0.36.0 // indirect
4449
github.com/prometheus/procfs v0.7.3 // indirect
4550
github.com/sirupsen/logrus v1.8.1 // indirect
4651
github.com/spf13/cobra v1.4.0 // indirect
4752
github.com/stretchr/objx v0.4.0 // indirect
4853
go.uber.org/atomic v1.9.0 // indirect
4954
go.uber.org/goleak v1.1.12 // indirect
5055
go.uber.org/multierr v1.8.0 // indirect
51-
golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect
52-
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
56+
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
57+
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect
5358
golang.org/x/text v0.3.7 // indirect
5459
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
5560
google.golang.org/protobuf v1.28.0 // indirect
5661
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
57-
gopkg.in/yaml.v3 v3.0.1 // indirect
5862
gotest.tools/v3 v3.1.0 // indirect
5963
)
6064

go.sum

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,14 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl
4040
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
4141
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
4242
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
43+
github.com/Depado/bfchroma/v2 v2.0.0 h1:IRpN9BPkNwEpR6w1ectIcNWOuhDSLx+8f1pn83fzxx8=
44+
github.com/Depado/bfchroma/v2 v2.0.0/go.mod h1:wFwW/Pw8Tnd0irzgO9Zxtxgzp3aPS8qBWlyadxujxmw=
4345
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
4446
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
4547
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
48+
github.com/alecthomas/chroma/v2 v2.2.0 h1:Aten8jfQwUqEdadVFFjNyjx7HTexhKP0XuqBG67mRDY=
49+
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
50+
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae h1:zzGwJfFlFGD94CyyYwCJeSuD32Gj9GTaSi5y9hoVzdY=
4651
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
4752
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
4853
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -88,6 +93,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
8893
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
8994
github.com/digineo/afero v1.8.3-0.20220418112931-7c60862cbc10 h1:JyjF4yzQAShaZBn+CFPPyvU/yQccXs1p9+RzqC0gJmc=
9095
github.com/digineo/afero v1.8.3-0.20220418112931-7c60862cbc10/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
96+
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
97+
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
9198
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
9299
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
93100
github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
@@ -290,8 +297,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
290297
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
291298
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
292299
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
293-
github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE=
294-
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
300+
github.com/prometheus/common v0.36.0 h1:78hJTing+BLYLjhXE+Z2BubeEymH5Lr0/Mt8FKkxxYo=
301+
github.com/prometheus/common v0.36.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
295302
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
296303
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
297304
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -303,6 +310,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
303310
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
304311
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
305312
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
313+
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
306314
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
307315
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
308316
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -449,8 +457,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
449457
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
450458
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
451459
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
452-
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
453-
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
460+
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
461+
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
454462
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
455463
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
456464
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -528,8 +536,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
528536
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
529537
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
530538
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
531-
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
532-
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
539+
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
540+
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
533541
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
534542
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
535543
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

service/service.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"time"
1111

12+
"github.com/digineo/texd/docs"
1213
"github.com/digineo/texd/exec"
1314
"github.com/digineo/texd/metrics"
1415
"github.com/digineo/texd/refstore"
@@ -87,6 +88,7 @@ func (svc *service) routes() http.Handler {
8788
r := mux.NewRouter()
8889
r.HandleFunc("/", HandleUI).Methods(http.MethodGet)
8990
r.PathPrefix("/assets/").Handler(HandleAssets()).Methods(http.MethodGet)
91+
r.PathPrefix("/docs").Handler(http.StripPrefix("/docs", docs.Handler())).Methods(http.MethodGet)
9092

9193
render := http.Handler(http.HandlerFunc(svc.HandleRender))
9294
if max := svc.maxJobSize; max > 0 {

0 commit comments

Comments
 (0)