Skip to content

Commit a0dc343

Browse files
committed
feat[close #4]: Replace the Roff Implementation from orchidlib with ours
1 parent 146019c commit a0dc343

File tree

7 files changed

+191
-17
lines changed

7 files changed

+191
-17
lines changed

examples/v1/task-manager/go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ go 1.21.1
44

55
require (
66
fyne.io/fyne/v2 v2.4.3
7-
github.com/vanilla-os/sdk v0.0.0-20240210103031-e14d94619689
7+
github.com/vanilla-os/sdk v0.0.0
88
)
99

10+
replace github.com/vanilla-os/sdk => ../../..
11+
1012
require (
1113
atomicgo.dev/cursor v0.1.1 // indirect
1214
atomicgo.dev/keyboard v0.2.8 // indirect
@@ -49,7 +51,6 @@ require (
4951
github.com/tevino/abool v1.2.0 // indirect
5052
github.com/tklauser/go-sysconf v0.3.13 // indirect
5153
github.com/tklauser/numcpus v0.7.0 // indirect
52-
github.com/vanilla-os/orchid v0.5.0 // indirect
5354
github.com/vorlif/spreak v0.6.0 // indirect
5455
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
5556
github.com/yuin/goldmark v1.5.5 // indirect

examples/v1/task-manager/go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,6 @@ github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08
354354
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
355355
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
356356
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
357-
github.com/vanilla-os/orchid v0.5.0 h1:QAOjJ2VcyND5TxK0XYUEu+dysxXicRHhV6i/07S47mk=
358-
github.com/vanilla-os/orchid v0.5.0/go.mod h1:dNPvHxofO4hEXodEKXp0nLQDZhoHh8evCUXc6X1xLao=
359-
github.com/vanilla-os/sdk v0.0.0-20240210103031-e14d94619689 h1:kA7D0yuYsTvXcE5ptVEex4rDmQ8tqmXneztyWXlaIvo=
360-
github.com/vanilla-os/sdk v0.0.0-20240210103031-e14d94619689/go.mod h1:o53W4jRWEOlwnkE4xndU4KnlKAQeOWNLIQqIQ51s3JE=
361357
github.com/vorlif/spreak v0.6.0 h1:+WrtSGKx9zcZy8d/Tp6t+OA3x9RgmA8TQYPzQ+U7Ddc=
362358
github.com/vorlif/spreak v0.6.0/go.mod h1:vcqv4dB1XgHpxIXhV5C+8EgqlzKfL37Atj2O/bOB1Bw=
363359
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ require (
1414
github.com/spf13/cobra v1.8.0
1515
github.com/spf13/viper v1.14.0
1616
github.com/stretchr/testify v1.8.4
17-
github.com/vanilla-os/orchid v0.5.0
1817
github.com/vorlif/spreak v0.6.0
1918
golang.org/x/sys v0.16.0
2019
golang.org/x/text v0.14.0

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,6 @@ github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08
265265
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
266266
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
267267
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
268-
github.com/vanilla-os/orchid v0.5.0 h1:QAOjJ2VcyND5TxK0XYUEu+dysxXicRHhV6i/07S47mk=
269-
github.com/vanilla-os/orchid v0.5.0/go.mod h1:dNPvHxofO4hEXodEKXp0nLQDZhoHh8evCUXc6X1xLao=
270268
github.com/vorlif/spreak v0.6.0 h1:+WrtSGKx9zcZy8d/Tp6t+OA3x9RgmA8TQYPzQ+U7Ddc=
271269
github.com/vorlif/spreak v0.6.0/go.mod h1:vcqv4dB1XgHpxIXhV5C+8EgqlzKfL37Atj2O/bOB1Bw=
272270
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=

pkg/v1/cli/cli.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
package cli
22

33
import (
4+
"fmt"
5+
"time"
6+
47
"github.com/spf13/cobra"
5-
"github.com/vanilla-os/orchid/roff"
68
"github.com/vanilla-os/sdk/pkg/v1/cli/types"
9+
"github.com/vanilla-os/sdk/pkg/v1/roff"
710
)
811

9-
// TODO:
10-
// This is a porting of the Cobra implemention from the orchid library
11-
// the roff implementation is not yet implemented, we still use the old
12-
// implementation from the orchid library
13-
1412
// NewCLI sets up the CLI for the application using CLIOptions.
1513
func NewCLI(options *types.CLIOptions) *Command {
1614
rootCmd := &cobra.Command{
@@ -23,6 +21,8 @@ func NewCLI(options *types.CLIOptions) *Command {
2321
Command: rootCmd,
2422
}
2523

24+
cli.addManCommand()
25+
2626
return cli
2727
}
2828

@@ -118,6 +118,23 @@ func NewCommandCustom(cmd *cobra.Command) *Command {
118118
}
119119
}
120120

121+
func (c *Command) addManCommand() {
122+
manCmd := NewCommandRunE(
123+
"man",
124+
"generate the CLI manpage",
125+
"Generate the man page for this command",
126+
func(cmd *cobra.Command, args []string) error {
127+
d := roff.NewDocument()
128+
d.Heading(1, c.Name(), c.Short, time.Now())
129+
c.doc(d)
130+
fmt.Print(d.String())
131+
return nil
132+
},
133+
)
134+
135+
c.AddCommand(manCmd)
136+
}
137+
121138
func (c *Command) doc(d *roff.Document) {
122139
c.docName(d)
123140
c.docSynopsis(d)
@@ -157,8 +174,10 @@ func (c *Command) docDescription(d *roff.Document) {
157174
func (c *Command) docOptions(d *roff.Document) {
158175
d.SubSection("Options")
159176
d.Text(c.Flags().FlagUsages())
160-
d.SubSection("Global Options")
161-
d.Text(c.Parent().PersistentFlags().FlagUsages())
177+
if parent := c.Parent(); parent != nil {
178+
d.SubSection("Global Options")
179+
d.Text(parent.PersistentFlags().FlagUsages())
180+
}
162181
d.EndSection()
163182
}
164183
func (c *Command) docExamples(d *roff.Document) {

pkg/v1/roff/roff.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package roff
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"github.com/vanilla-os/sdk/pkg/v1/roff/types"
10+
)
11+
12+
// Document wraps types.Document adding helper methods.
13+
type Document struct {
14+
types.Document
15+
}
16+
17+
// NewDocument creates a new roff document.
18+
func NewDocument() *Document {
19+
return &Document{}
20+
}
21+
22+
func (d *Document) writef(format string, args ...any) {
23+
if bytes.HasSuffix(d.Buffer.Bytes(), []byte("\n")) && strings.HasPrefix(format, "\n") {
24+
format = strings.TrimPrefix(format, "\n")
25+
}
26+
fmt.Fprintf(&d.Buffer, format, args...)
27+
}
28+
29+
func (d *Document) writelnf(format string, args ...any) {
30+
d.writef(format+"\n", args...)
31+
}
32+
33+
// Heading writes the document heading.
34+
func (d *Document) Heading(section uint, title, desc string, ts time.Time) {
35+
d.writef(types.TitleHeading, strings.ToUpper(title), section, title, ts.Format("2006-01-02"), desc)
36+
}
37+
38+
// Paragraph starts a new paragraph.
39+
func (d *Document) Paragraph() { d.writelnf(types.Paragraph) }
40+
41+
// Indent increases the indentation level.
42+
func (d *Document) Indent(n int) {
43+
if n >= 0 {
44+
d.writelnf(types.Indent+" %d", n)
45+
} else {
46+
d.writelnf(types.Indent)
47+
}
48+
}
49+
50+
// IndentEnd decreases the indentation level.
51+
func (d *Document) IndentEnd() { d.writelnf(types.IndentEnd) }
52+
53+
// TaggedParagraph starts a tagged paragraph.
54+
func (d *Document) TaggedParagraph(indentation int) {
55+
if indentation >= 0 {
56+
d.writelnf(types.TaggedParagraph+" %d", indentation)
57+
} else {
58+
d.writelnf(types.TaggedParagraph)
59+
}
60+
}
61+
62+
// List writes a list item.
63+
func (d *Document) List(text string) {
64+
d.writelnf(types.IndentedParagraph+" \\(bu 3\n%s", escapeText(strings.TrimSpace(text)))
65+
}
66+
67+
// Section writes a section heading.
68+
func (d *Document) Section(text string) {
69+
d.writelnf(types.SectionHeading, strings.ToUpper(text))
70+
}
71+
72+
// SubSection writes a subsection heading.
73+
func (d *Document) SubSection(text string) {
74+
d.writelnf(types.SubSectionHeading, strings.ToUpper(text))
75+
}
76+
77+
// EndSection ends the current section.
78+
func (d *Document) EndSection() { d.writelnf("") }
79+
80+
// EndSubSection ends the current subsection.
81+
func (d *Document) EndSubSection() { d.writelnf("") }
82+
83+
// Text writes text handling basic lists.
84+
func (d *Document) Text(text string) {
85+
inList := false
86+
for i, line := range strings.Split(text, "\n") {
87+
if i > 0 && !inList {
88+
d.Paragraph()
89+
}
90+
if strings.HasPrefix(line, "*") {
91+
if !inList {
92+
d.Indent(-1)
93+
inList = true
94+
}
95+
d.List(line[1:])
96+
} else {
97+
if inList {
98+
d.IndentEnd()
99+
inList = false
100+
}
101+
d.writef(escapeText(line))
102+
}
103+
}
104+
}
105+
106+
// TextBold writes bold text.
107+
func (d *Document) TextBold(text string) {
108+
d.writef(types.Bold)
109+
d.Text(text)
110+
d.writef(types.PreviousFont)
111+
}
112+
113+
// TextItalic writes italic text.
114+
func (d *Document) TextItalic(text string) {
115+
d.writef(types.Italic)
116+
d.Text(text)
117+
d.writef(types.PreviousFont)
118+
}
119+
120+
// String returns the document as a string.
121+
func (d *Document) String() string { return d.Buffer.String() }
122+
123+
func escapeText(s string) string {
124+
s = strings.ReplaceAll(s, `\`, `\e`)
125+
s = strings.ReplaceAll(s, ".", "\\&.")
126+
return s
127+
}

pkg/v1/roff/types/roff.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package types
2+
3+
import "bytes"
4+
5+
// Document represents a roff document buffer.
6+
type Document struct {
7+
Buffer bytes.Buffer
8+
}
9+
10+
const (
11+
// TitleHeading formats the document title header.
12+
TitleHeading = `.TH %[1]s %[2]d "%[4]s" "%[3]s" "%[5]s"`
13+
// Paragraph macro.
14+
Paragraph = "\n.PP"
15+
// Indent begins a relative indent block.
16+
Indent = "\n.RS"
17+
// IndentEnd ends an indent block.
18+
IndentEnd = "\n.RE"
19+
// IndentedParagraph writes an indented paragraph.
20+
IndentedParagraph = "\n.IP"
21+
// SectionHeading macro.
22+
SectionHeading = "\n.SH %s"
23+
// SubSectionHeading macro.
24+
SubSectionHeading = "\n.SS %s"
25+
// TaggedParagraph macro.
26+
TaggedParagraph = "\n.TP"
27+
28+
// Bold escape sequence.
29+
Bold = `\fB`
30+
// Italic escape sequence.
31+
Italic = `\fI`
32+
// PreviousFont resets the font.
33+
PreviousFont = `\fP`
34+
)

0 commit comments

Comments
 (0)