support custom bullet lengths in tty and roff
This commit is contained in:
parent
cff44cc943
commit
0ddb884813
23
lib.go
23
lib.go
@ -62,18 +62,17 @@ type SyntaxItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
typ int
|
typ int
|
||||||
text Txt
|
text Txt
|
||||||
titleLevel int
|
titleLevel int
|
||||||
items []ListItem
|
items []ListItem
|
||||||
definitions []DefinitionItem
|
definitions []DefinitionItem
|
||||||
rows []TableRow
|
rows []TableRow
|
||||||
syntax SyntaxItem
|
syntax SyntaxItem
|
||||||
wrapWidth int
|
wrapWidth int
|
||||||
wrapWidthFirst int
|
indent int
|
||||||
indent int
|
indentFirst int
|
||||||
indentFirst int
|
man struct {
|
||||||
man struct {
|
|
||||||
section int
|
section int
|
||||||
date time.Time
|
date time.Time
|
||||||
version string
|
version string
|
||||||
|
|||||||
214
runoff.go
214
runoff.go
@ -13,21 +13,45 @@ func manPageDate(d time.Time) string {
|
|||||||
return fmt.Sprintf("%v %d", d.Month(), d.Year())
|
return fmt.Sprintf("%v %d", d.Month(), d.Year())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func escapeRoffString(s string, additionalEscape ...string) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
w, f := writeWith(&b, escapeRoff(additionalEscape...))
|
||||||
|
write(w, s)
|
||||||
|
f()
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func roffTextLength(t Txt) int {
|
||||||
|
var l int
|
||||||
|
if len(t.cat) > 0 {
|
||||||
|
for i, tc := range t.cat {
|
||||||
|
if i > 0 {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
|
||||||
|
l += roffTextLength(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.link == "" {
|
||||||
|
return len([]rune(t.text))
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.text == "" {
|
||||||
|
return len([]rune(t.link))
|
||||||
|
}
|
||||||
|
|
||||||
|
return len([]rune(t.text)) + len([]rune(t.link)) + 3
|
||||||
|
}
|
||||||
|
|
||||||
func roffTextToString(t Txt) string {
|
func roffTextToString(t Txt) string {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
renderRoffText(&b, t)
|
renderRoffText(&b, t)
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func roffDefinitionNames(d []DefinitionItem) []string {
|
|
||||||
var n []string
|
|
||||||
for _, di := range d {
|
|
||||||
n = append(n, roffTextToString(di.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func roffCellTexts(r []TableRow) [][]string {
|
func roffCellTexts(r []TableRow) [][]string {
|
||||||
var cellTexts [][]string
|
var cellTexts [][]string
|
||||||
for _, row := range r {
|
for _, row := range r {
|
||||||
@ -129,90 +153,154 @@ func renderRoffParagraph(w io.Writer, e Entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renderRoffList(w io.Writer, e Entry) {
|
func renderRoffList(w io.Writer, e Entry) {
|
||||||
|
bullets := make([]string, len(e.items))
|
||||||
|
bulletLengths := make([]int, len(e.items))
|
||||||
|
for i := range e.items {
|
||||||
|
itemStyle := mergeItemStyles(e.items[i].style)
|
||||||
|
if itemStyle.noBullet {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if itemStyle.bullet == "" {
|
||||||
|
bullets[i] = "\\(bu"
|
||||||
|
bulletLengths[i] = 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bullets[i] = escapeRoffString(itemStyle.bullet, " ", "\\~")
|
||||||
|
bulletLengths[i] = len([]rune(itemStyle.bullet))
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxBulletLength int
|
||||||
|
for _, l := range bulletLengths {
|
||||||
|
if l > maxBulletLength {
|
||||||
|
maxBulletLength = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range bullets {
|
||||||
|
if bulletLengths[i] == maxBulletLength {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bullets[i] = fmt.Sprintf(
|
||||||
|
"%s%s",
|
||||||
|
bullets[i],
|
||||||
|
timesn("\\~", maxBulletLength-bulletLengths[i]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for i, item := range e.items {
|
for i, item := range e.items {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write(w, "\n.br\n")
|
write(w, "\n.br\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
indent := e.indent
|
||||||
bullet string
|
if maxBulletLength > 0 {
|
||||||
bulletIndent int
|
indent += maxBulletLength + 1
|
||||||
)
|
}
|
||||||
|
|
||||||
itemStyle := mergeItemStyles(item.style)
|
write(w, ".in ", indent, "\n.ti ", e.indent+e.indentFirst, "\n")
|
||||||
if !itemStyle.noBullet {
|
write(w, bullets[i])
|
||||||
if itemStyle.bullet == "" {
|
if maxBulletLength > 0 {
|
||||||
bullet = "\\(bu "
|
write(w, "\\~")
|
||||||
bulletIndent = 2
|
|
||||||
} else {
|
|
||||||
bullet = itemStyle.bullet + " "
|
|
||||||
bulletIndent = len([]rune(bullet))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write(w, ".in ", e.indent+bulletIndent, "\n.ti ", e.indent+e.indentFirst, "\n")
|
|
||||||
write(w, bullet)
|
|
||||||
renderRoffText(w, item.text)
|
renderRoffText(w, item.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRoffNumberedList(w io.Writer, e Entry) {
|
func renderRoffNumberedList(w io.Writer, e Entry) {
|
||||||
maxDigits := numDigits(len(e.items))
|
items := make([]ListItem, len(e.items))
|
||||||
for i, item := range e.items {
|
for i := range e.items {
|
||||||
if i > 0 {
|
items[i] = Item(
|
||||||
write(w, "\n.br\n")
|
e.items[i].text,
|
||||||
}
|
append(e.items[i].style, Bullet(fmt.Sprintf("%d.", i+1)))...,
|
||||||
|
)
|
||||||
write(w, ".in ", e.indent+maxDigits+2, "\n.ti ", e.indent+e.indentFirst, "\n")
|
|
||||||
write(w, padRight(fmt.Sprintf("%d.", i+1), maxDigits+2))
|
|
||||||
renderRoffText(w, item.text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.typ = list
|
||||||
|
e.items = items
|
||||||
|
renderRoffList(w, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRoffDefinitions(w io.Writer, e Entry) {
|
func renderRoffDefinitions(w io.Writer, e Entry) {
|
||||||
names := roffDefinitionNames(e.definitions)
|
itemStyles := make([]ItemStyle, len(e.definitions))
|
||||||
maxNameLength := maxLength(names)
|
for i := range e.definitions {
|
||||||
|
itemStyles[i] = mergeItemStyles(e.definitions[i].style)
|
||||||
|
}
|
||||||
|
|
||||||
|
bullets := make([]string, len(itemStyles))
|
||||||
|
bulletLengths := make([]int, len(itemStyles))
|
||||||
|
for i := range itemStyles {
|
||||||
|
if itemStyles[i].noBullet {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if itemStyles[i].bullet == "" {
|
||||||
|
bullets[i] = "\\(bu"
|
||||||
|
bulletLengths[i] = 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bullets[i] = escapeRoffString(itemStyles[i].bullet, " ", "\\~")
|
||||||
|
bulletLengths[i] = len([]rune(itemStyles[i].bullet))
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxBulletLength int
|
||||||
|
for i := range bulletLengths {
|
||||||
|
if bulletLengths[i] > maxBulletLength {
|
||||||
|
maxBulletLength = bulletLengths[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nameLengths := make([]int, len(e.definitions))
|
||||||
|
for i := range e.definitions {
|
||||||
|
nameLengths[i] = roffTextLength(e.definitions[i].name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxNameLength int
|
||||||
|
for i := range nameLengths {
|
||||||
|
if nameLengths[i] > maxNameLength {
|
||||||
|
maxNameLength = nameLengths[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i, definition := range e.definitions {
|
for i, definition := range e.definitions {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write(w, "\n.br\n")
|
write(w, "\n.br\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
var bullet string
|
indent := e.indent + maxNameLength + 2
|
||||||
padLength := 2
|
if maxBulletLength > 0 {
|
||||||
itemStyle := mergeItemStyles(definition.style)
|
indent += maxBulletLength + 1
|
||||||
if !itemStyle.noBullet {
|
}
|
||||||
if itemStyle.bullet == "" {
|
|
||||||
bullet = "\\(bu "
|
write(w, ".in ", indent, "\n.ti ", e.indent+e.indentFirst, "\n")
|
||||||
padLength = 4
|
write(w, bullets[i])
|
||||||
} else {
|
if maxBulletLength > 0 {
|
||||||
bullet = itemStyle.bullet + " "
|
write(w, timesn("\\~", maxBulletLength-bulletLengths[i]+1))
|
||||||
padLength = len([]rune(bullet)) + 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write(w, ".in ", e.indent+maxNameLength+padLength, "\n.ti ", e.indent+e.indentFirst, "\n")
|
|
||||||
write(w, bullet)
|
|
||||||
renderRoffText(w, definition.name)
|
renderRoffText(w, definition.name)
|
||||||
write(w, ":", timesn("\\~", maxNameLength-len([]rune(names[i]))+1))
|
write(w, ":", timesn("\\~", maxNameLength-nameLengths[i]+1))
|
||||||
renderRoffText(w, definition.value)
|
renderRoffText(w, definition.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRoffNumberedDefinitions(w io.Writer, e Entry) {
|
func renderRoffNumberedDefinitions(w io.Writer, e Entry) {
|
||||||
maxDigits := numDigits(len(e.definitions))
|
defs := make([]DefinitionItem, len(e.definitions))
|
||||||
names := roffDefinitionNames(e.definitions)
|
for i := range e.definitions {
|
||||||
maxNameLength := maxLength(names)
|
defs[i] = Definition(
|
||||||
for i, definition := range e.definitions {
|
e.definitions[i].name,
|
||||||
if i > 0 {
|
e.definitions[i].value,
|
||||||
write(w, "\n.br\n")
|
append(e.definitions[i].style, Bullet(fmt.Sprintf("%d.", i+1)))...,
|
||||||
}
|
)
|
||||||
|
|
||||||
write(w, ".in ", e.indent+maxDigits+maxNameLength+4, "\n.ti ", e.indent+e.indentFirst, "\n")
|
|
||||||
write(w, padRight(fmt.Sprintf("%d.", i+1), maxDigits+2))
|
|
||||||
renderRoffText(w, definition.name)
|
|
||||||
write(w, ":", timesn("\\~", maxNameLength-len([]rune(names[i]))+1))
|
|
||||||
renderRoffText(w, definition.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.typ = definitions
|
||||||
|
e.definitions = defs
|
||||||
|
renderRoffDefinitions(w, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRoffTable(w io.Writer, e Entry) {
|
func renderRoffTable(w io.Writer, e Entry) {
|
||||||
|
|||||||
300
runoff_test.go
300
runoff_test.go
@ -144,39 +144,39 @@ textfmt supports the following entries:
|
|||||||
.sp 1v
|
.sp 1v
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu CodeBlock
|
\(bu\~CodeBlock
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu DefinitionList
|
\(bu\~DefinitionList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu List
|
\(bu\~List
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedDefinitionList
|
\(bu\~NumberedDefinitionList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedList
|
\(bu\~NumberedList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Paragraph
|
\(bu\~Paragraph
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Syntax
|
\(bu\~Syntax
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Table
|
\(bu\~Table
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Title
|
\(bu\~Title
|
||||||
.br
|
.br
|
||||||
.sp 1v
|
.sp 1v
|
||||||
.in 0
|
.in 0
|
||||||
@ -186,39 +186,39 @@ textfmt supports the following entries:
|
|||||||
.sp 1v
|
.sp 1v
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu CodeBlock:\~\~\~\~\~\~\~\~\~\~\~\~\~\~a multiline block of code
|
\(bu\~CodeBlock:\~\~\~\~\~\~\~\~\~\~\~\~\~\~a multiline block of code
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu DefinitionList:\~\~\~\~\~\~\~\~\~a list of definitions like this one
|
\(bu\~DefinitionList:\~\~\~\~\~\~\~\~\~a list of definitions like this one
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu List:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a list of items
|
\(bu\~List:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a list of items
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedDefinitionList:\~numbered definitions
|
\(bu\~NumberedDefinitionList:\~numbered definitions
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedList:\~\~\~\~\~\~\~\~\~\~\~numbered list
|
\(bu\~NumberedList:\~\~\~\~\~\~\~\~\~\~\~numbered list
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Paragraph:\~\~\~\~\~\~\~\~\~\~\~\~\~\~paragraph of text
|
\(bu\~Paragraph:\~\~\~\~\~\~\~\~\~\~\~\~\~\~paragraph of text
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Syntax:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a syntax expression
|
\(bu\~Syntax:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a syntax expression
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Table:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a table
|
\(bu\~Table:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a table
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Title:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a title
|
\(bu\~Title:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a title
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -354,39 +354,39 @@ textfmt supports the following entries:
|
|||||||
.sp 1v
|
.sp 1v
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu CodeBlock
|
\(bu\~CodeBlock
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu DefinitionList
|
\(bu\~DefinitionList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu List
|
\(bu\~List
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedDefinitionList
|
\(bu\~NumberedDefinitionList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedList
|
\(bu\~NumberedList
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Paragraph
|
\(bu\~Paragraph
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Syntax
|
\(bu\~Syntax
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Table
|
\(bu\~Table
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Title
|
\(bu\~Title
|
||||||
.br
|
.br
|
||||||
.sp 1v
|
.sp 1v
|
||||||
.in 0
|
.in 0
|
||||||
@ -396,39 +396,39 @@ textfmt supports the following entries:
|
|||||||
.sp 1v
|
.sp 1v
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu CodeBlock:\~\~\~\~\~\~\~\~\~\~\~\~\~\~a multiline block of code
|
\(bu\~CodeBlock:\~\~\~\~\~\~\~\~\~\~\~\~\~\~a multiline block of code
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu DefinitionList:\~\~\~\~\~\~\~\~\~a list of definitions like this one
|
\(bu\~DefinitionList:\~\~\~\~\~\~\~\~\~a list of definitions like this one
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu List:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a list of items
|
\(bu\~List:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a list of items
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedDefinitionList:\~numbered definitions
|
\(bu\~NumberedDefinitionList:\~numbered definitions
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu NumberedList:\~\~\~\~\~\~\~\~\~\~\~numbered list
|
\(bu\~NumberedList:\~\~\~\~\~\~\~\~\~\~\~numbered list
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Paragraph:\~\~\~\~\~\~\~\~\~\~\~\~\~\~paragraph of text
|
\(bu\~Paragraph:\~\~\~\~\~\~\~\~\~\~\~\~\~\~paragraph of text
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Syntax:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a syntax expression
|
\(bu\~Syntax:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a syntax expression
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Table:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a table
|
\(bu\~Table:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a table
|
||||||
.br
|
.br
|
||||||
.in 26
|
.in 26
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu Title:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a title
|
\(bu\~Title:\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~\~a title
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -781,15 +781,15 @@ This is a paragraph.
|
|||||||
|
|
||||||
const expect = `.in 2
|
const expect = `.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is an item
|
\(bu\~this is an item
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is another item
|
\(bu\~this is another item
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is a third item
|
\(bu\~this is a third item
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -817,15 +817,15 @@ This is a paragraph.
|
|||||||
|
|
||||||
const expect = `.in 6
|
const expect = `.in 6
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is an item
|
\(bu\~this is an item
|
||||||
.br
|
.br
|
||||||
.in 6
|
.in 6
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is another item
|
\(bu\~this is another item
|
||||||
.br
|
.br
|
||||||
.in 6
|
.in 6
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is a third item
|
\(bu\~this is a third item
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -853,15 +853,15 @@ This is a paragraph.
|
|||||||
|
|
||||||
const expect = `.in 0
|
const expect = `.in 0
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is an item
|
\(bu\~this is an item
|
||||||
.br
|
.br
|
||||||
.in 0
|
.in 0
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is another item
|
\(bu\~this is another item
|
||||||
.br
|
.br
|
||||||
.in 0
|
.in 0
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu this is a third item
|
\(bu\~this is a third item
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -889,15 +889,15 @@ This is a paragraph.
|
|||||||
|
|
||||||
const expect = `.in 4
|
const expect = `.in 4
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is an item
|
\(bu\~this is an item
|
||||||
.br
|
.br
|
||||||
.in 4
|
.in 4
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is another item
|
\(bu\~this is another item
|
||||||
.br
|
.br
|
||||||
.in 4
|
.in 4
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu this is a third item
|
\(bu\~this is a third item
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -922,15 +922,15 @@ This is a paragraph.
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
* foo bar baz
|
*\~foo bar baz
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
* qux
|
*\~qux
|
||||||
.br
|
.br
|
||||||
.in 2
|
.in 2
|
||||||
.ti 0
|
.ti 0
|
||||||
* quux
|
*\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -955,15 +955,15 @@ This is a paragraph.
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 3
|
.in 3
|
||||||
.ti 0
|
.ti 0
|
||||||
=> foo bar baz
|
=>\~foo bar baz
|
||||||
.br
|
.br
|
||||||
.in 3
|
.in 3
|
||||||
.ti 0
|
.ti 0
|
||||||
=> qux
|
=>\~qux
|
||||||
.br
|
.br
|
||||||
.in 3
|
.in 3
|
||||||
.ti 0
|
.ti 0
|
||||||
=> quux
|
=>\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -997,6 +997,72 @@ qux
|
|||||||
.in 0
|
.in 0
|
||||||
.ti 0
|
.ti 0
|
||||||
quux
|
quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("varying bullet length", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.List(
|
||||||
|
textfmt.Item(textfmt.Text("foo bar baz"), textfmt.Bullet("=>")),
|
||||||
|
textfmt.Item(textfmt.Text("qux"), textfmt.Bullet("==>")),
|
||||||
|
textfmt.Item(textfmt.Text("quux"), textfmt.Bullet("=>")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Runoff(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
.in 4
|
||||||
|
.ti 0
|
||||||
|
=>\~\~foo bar baz
|
||||||
|
.br
|
||||||
|
.in 4
|
||||||
|
.ti 0
|
||||||
|
==>\~qux
|
||||||
|
.br
|
||||||
|
.in 4
|
||||||
|
.ti 0
|
||||||
|
=>\~\~quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("escape custom bullet", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.List(
|
||||||
|
textfmt.Item(textfmt.Text("foo bar baz"), textfmt.Bullet(".>")),
|
||||||
|
textfmt.Item(textfmt.Text("qux"), textfmt.Bullet("=>")),
|
||||||
|
textfmt.Item(textfmt.Text("quux"), textfmt.Bullet("=>")),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Runoff(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
.in 3
|
||||||
|
.ti 0
|
||||||
|
\&.>\~foo bar baz
|
||||||
|
.br
|
||||||
|
.in 3
|
||||||
|
.ti 0
|
||||||
|
=>\~qux
|
||||||
|
.br
|
||||||
|
.in 3
|
||||||
|
.ti 0
|
||||||
|
=>\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1241,15 +1307,15 @@ quux
|
|||||||
|
|
||||||
const expect = `.in 9
|
const expect = `.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu red:\~\~\~looks like strawberry
|
\(bu\~red:\~\~\~looks like strawberry
|
||||||
.br
|
.br
|
||||||
.in 9
|
.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu green:\~looks like grass
|
\(bu\~green:\~looks like grass
|
||||||
.br
|
.br
|
||||||
.in 9
|
.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu blue:\~\~looks like sky
|
\(bu\~blue:\~\~looks like sky
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -1277,15 +1343,15 @@ quux
|
|||||||
|
|
||||||
const expect = `.in 13
|
const expect = `.in 13
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu red:\~\~\~looks like strawberry
|
\(bu\~red:\~\~\~looks like strawberry
|
||||||
.br
|
.br
|
||||||
.in 13
|
.in 13
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu green:\~looks like grass
|
\(bu\~green:\~looks like grass
|
||||||
.br
|
.br
|
||||||
.in 13
|
.in 13
|
||||||
.ti 4
|
.ti 4
|
||||||
\(bu blue:\~\~looks like sky
|
\(bu\~blue:\~\~looks like sky
|
||||||
`
|
`
|
||||||
|
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
@ -1314,15 +1380,15 @@ quux
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 3
|
.in 3
|
||||||
.ti 3
|
.ti 3
|
||||||
\(bu red:\~\~\~looks like strawberry
|
\(bu\~red:\~\~\~looks like strawberry
|
||||||
.br
|
.br
|
||||||
.in 3
|
.in 3
|
||||||
.ti 3
|
.ti 3
|
||||||
\(bu green:\~looks like grass
|
\(bu\~green:\~looks like grass
|
||||||
.br
|
.br
|
||||||
.in 3
|
.in 3
|
||||||
.ti 3
|
.ti 3
|
||||||
\(bu blue:\~\~looks like sky
|
\(bu\~blue:\~\~looks like sky
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1351,15 +1417,15 @@ quux
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 13
|
.in 13
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu red:\~\~\~looks like strawberry
|
\(bu\~red:\~\~\~looks like strawberry
|
||||||
.br
|
.br
|
||||||
.in 13
|
.in 13
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu green:\~looks like grass
|
\(bu\~green:\~looks like grass
|
||||||
.br
|
.br
|
||||||
.in 13
|
.in 13
|
||||||
.ti 0
|
.ti 0
|
||||||
\(bu blue:\~\~looks like sky
|
\(bu\~blue:\~\~looks like sky
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1396,15 +1462,15 @@ quux
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 9
|
.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
* one:\~\~\~foo bar baz
|
*\~one:\~\~\~foo bar baz
|
||||||
.br
|
.br
|
||||||
.in 9
|
.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
* two:\~\~\~qux
|
*\~two:\~\~\~qux
|
||||||
.br
|
.br
|
||||||
.in 9
|
.in 9
|
||||||
.ti 0
|
.ti 0
|
||||||
* three:\~quux
|
*\~three:\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1441,15 +1507,15 @@ quux
|
|||||||
const expect = `
|
const expect = `
|
||||||
.in 10
|
.in 10
|
||||||
.ti 0
|
.ti 0
|
||||||
=> one:\~\~\~foo bar baz
|
=>\~one:\~\~\~foo bar baz
|
||||||
.br
|
.br
|
||||||
.in 10
|
.in 10
|
||||||
.ti 0
|
.ti 0
|
||||||
=> two:\~\~\~qux
|
=>\~two:\~\~\~qux
|
||||||
.br
|
.br
|
||||||
.in 10
|
.in 10
|
||||||
.ti 0
|
.ti 0
|
||||||
=> three:\~quux
|
=>\~three:\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1495,6 +1561,96 @@ two:\~\~\~qux
|
|||||||
.in 7
|
.in 7
|
||||||
.ti 0
|
.ti 0
|
||||||
three:\~quux
|
three:\~quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("varying bullet length", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.DefinitionList(
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("one"),
|
||||||
|
textfmt.Text("foo bar baz"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("two"),
|
||||||
|
textfmt.Text("qux"),
|
||||||
|
textfmt.Bullet("==>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("three"),
|
||||||
|
textfmt.Text("quux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Runoff(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
.in 11
|
||||||
|
.ti 0
|
||||||
|
=>\~\~one:\~\~\~foo bar baz
|
||||||
|
.br
|
||||||
|
.in 11
|
||||||
|
.ti 0
|
||||||
|
==>\~two:\~\~\~qux
|
||||||
|
.br
|
||||||
|
.in 11
|
||||||
|
.ti 0
|
||||||
|
=>\~\~three:\~quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("escape custom bullet", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.DefinitionList(
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("one"),
|
||||||
|
textfmt.Text("foo bar baz"),
|
||||||
|
textfmt.Bullet(".>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("two"),
|
||||||
|
textfmt.Text("qux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("three"),
|
||||||
|
textfmt.Text("quux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Runoff(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
.in 10
|
||||||
|
.ti 0
|
||||||
|
\&.>\~one:\~\~\~foo bar baz
|
||||||
|
.br
|
||||||
|
.in 10
|
||||||
|
.ti 0
|
||||||
|
=>\~two:\~\~\~qux
|
||||||
|
.br
|
||||||
|
.in 10
|
||||||
|
.ti 0
|
||||||
|
=>\~three:\~quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
|
|||||||
139
teletype.go
139
teletype.go
@ -65,11 +65,10 @@ func renderTTYTitle(w io.Writer, e Entry) {
|
|||||||
func renderTTYParagraph(w io.Writer, e Entry) {
|
func renderTTYParagraph(w io.Writer, e Entry) {
|
||||||
var indentation wrapper
|
var indentation wrapper
|
||||||
indentFirst := e.indent + e.indentFirst
|
indentFirst := e.indent + e.indentFirst
|
||||||
wrapWidthFirst := e.wrapWidth + e.wrapWidthFirst
|
|
||||||
if e.wrapWidth == 0 {
|
if e.wrapWidth == 0 {
|
||||||
indentation = indent(indentFirst, e.indent)
|
indentation = indent(indentFirst, e.indent)
|
||||||
} else {
|
} else {
|
||||||
indentation = wrapIndent(indentFirst, e.indent, wrapWidthFirst, e.wrapWidth)
|
indentation = wrapIndent(indentFirst, e.indent, e.wrapWidth, e.wrapWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
w, f := writeWith(w, indentation)
|
w, f := writeWith(w, indentation)
|
||||||
@ -78,95 +77,111 @@ func renderTTYParagraph(w io.Writer, e Entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func renderTTYList(w io.Writer, e Entry) {
|
func renderTTYList(w io.Writer, e Entry) {
|
||||||
for i, item := range e.items {
|
var bullets []string
|
||||||
if i > 0 {
|
for _, item := range e.items {
|
||||||
write(w, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
var p Entry
|
|
||||||
itemStyle := mergeItemStyles(item.style)
|
itemStyle := mergeItemStyles(item.style)
|
||||||
if itemStyle.noBullet {
|
if itemStyle.noBullet {
|
||||||
p = itemToParagraph(e, item.text)
|
bullets = append(bullets, "")
|
||||||
} else {
|
} else {
|
||||||
bullet := "-"
|
bullet := "-"
|
||||||
if itemStyle.bullet != "" {
|
if itemStyle.bullet != "" {
|
||||||
bullet = itemStyle.bullet
|
bullet = itemStyle.bullet
|
||||||
}
|
}
|
||||||
|
|
||||||
p = itemToParagraph(e, item.text, bullet)
|
bullets = append(bullets, bullet)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTTYParagraph(w, p)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func renderTTYNumberedList(w io.Writer, e Entry) {
|
maxBulletLength := maxLength(bullets)
|
||||||
maxDigits := numDigits(len(e.items))
|
for i := range bullets {
|
||||||
|
bullets[i] = padRight(bullets[i], maxBulletLength)
|
||||||
|
}
|
||||||
|
|
||||||
for i, item := range e.items {
|
for i, item := range e.items {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
write(w, "\n")
|
write(w, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
p := itemToParagraph(e, item.text, padRight(fmt.Sprintf("%d.", i+1), maxDigits+1))
|
p := itemToParagraph(e, item.text, bullets[i])
|
||||||
renderTTYParagraph(w, p)
|
renderTTYParagraph(w, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renderTTYNumberedList(w io.Writer, e Entry) {
|
||||||
|
var items []ListItem
|
||||||
|
for i, item := range e.items {
|
||||||
|
items = append(
|
||||||
|
items,
|
||||||
|
Item(
|
||||||
|
item.text,
|
||||||
|
append(item.style, Bullet(fmt.Sprintf("%d.", i+1)))...,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.typ = list
|
||||||
|
e.items = items
|
||||||
|
renderTTYList(w, e)
|
||||||
|
}
|
||||||
|
|
||||||
func renderTTYDefinitions(w io.Writer, e Entry) {
|
func renderTTYDefinitions(w io.Writer, e Entry) {
|
||||||
names := ttyDefinitionNames(e.definitions)
|
itemStyles := make([]ItemStyle, len(e.definitions))
|
||||||
maxNameLength := maxLength(names)
|
for i := range e.definitions {
|
||||||
for i, definition := range e.definitions {
|
itemStyles[i] = mergeItemStyles(e.definitions[i].style)
|
||||||
if i > 0 {
|
|
||||||
write(w, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
var bullet string
|
|
||||||
padLength := 1
|
|
||||||
itemStyle := mergeItemStyles(definition.style)
|
|
||||||
if !itemStyle.noBullet {
|
|
||||||
if itemStyle.bullet == "" {
|
|
||||||
bullet = "- "
|
|
||||||
padLength = 3
|
|
||||||
} else {
|
|
||||||
bullet = itemStyle.bullet + " "
|
|
||||||
padLength = len([]rune(bullet)) + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p := itemToParagraph(
|
|
||||||
e,
|
|
||||||
definition.value,
|
|
||||||
padRight(fmt.Sprintf("%s%s:", bullet, names[i]), maxNameLength+padLength),
|
|
||||||
)
|
|
||||||
|
|
||||||
renderTTYParagraph(w, p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bullets := make([]string, len(e.definitions))
|
||||||
|
for i := range e.definitions {
|
||||||
|
if itemStyles[i].noBullet {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if itemStyles[i].bullet == "" {
|
||||||
|
bullets[i] = "-"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bullets[i] = itemStyles[i].bullet
|
||||||
|
}
|
||||||
|
|
||||||
|
maxBulletLength := maxLength(bullets)
|
||||||
|
items := make([]ListItem, len(e.definitions))
|
||||||
|
for i := range e.definitions {
|
||||||
|
var bullet string
|
||||||
|
if maxBulletLength == 0 {
|
||||||
|
bullet = fmt.Sprintf("%s:", ttyTextToString(e.definitions[i].name))
|
||||||
|
} else {
|
||||||
|
bullet = fmt.Sprintf(
|
||||||
|
"%s %s:",
|
||||||
|
padRight(bullets[i], maxBulletLength),
|
||||||
|
ttyTextToString(e.definitions[i].name),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
items[i] = Item(e.definitions[i].value, Bullet(bullet))
|
||||||
|
}
|
||||||
|
|
||||||
|
e.typ = list
|
||||||
|
e.items = items
|
||||||
|
renderTTYList(w, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderTTYNumberedDefinitions(w io.Writer, e Entry) {
|
func renderTTYNumberedDefinitions(w io.Writer, e Entry) {
|
||||||
names := ttyDefinitionNames(e.definitions)
|
var defs []DefinitionItem
|
||||||
maxNameLength := maxLength(names)
|
|
||||||
maxDigits := numDigits(len(e.definitions))
|
|
||||||
for i, definition := range e.definitions {
|
for i, definition := range e.definitions {
|
||||||
if i > 0 {
|
defs = append(
|
||||||
write(w, "\n")
|
defs,
|
||||||
}
|
Definition(
|
||||||
|
definition.name,
|
||||||
p := itemToParagraph(
|
definition.value,
|
||||||
e,
|
append(definition.style, Bullet(fmt.Sprintf("%d.", i+1)))...,
|
||||||
definition.value,
|
|
||||||
padRight(
|
|
||||||
fmt.Sprintf(
|
|
||||||
"%s %s:",
|
|
||||||
padRight(fmt.Sprintf("%d.", i+1), maxDigits+1),
|
|
||||||
names[i],
|
|
||||||
),
|
|
||||||
maxNameLength+maxDigits+3,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
renderTTYParagraph(w, p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.typ = definitions
|
||||||
|
e.definitions = defs
|
||||||
|
renderTTYDefinitions(w, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ttyCellTexts(rows []TableRow) [][]string {
|
func ttyCellTexts(rows []TableRow) [][]string {
|
||||||
|
|||||||
141
teletype_test.go
141
teletype_test.go
@ -724,6 +724,65 @@ foo bar
|
|||||||
baz
|
baz
|
||||||
qux
|
qux
|
||||||
quux
|
quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("varying length bullets", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.Wrap(
|
||||||
|
textfmt.List(
|
||||||
|
textfmt.Item(textfmt.Text("foo bar baz"), textfmt.Bullet("=>")),
|
||||||
|
textfmt.Item(textfmt.Text("qux"), textfmt.Bullet("==>")),
|
||||||
|
textfmt.Item(textfmt.Text("quux"), textfmt.Bullet("=>")),
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Teletype(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
=> foo
|
||||||
|
bar
|
||||||
|
baz
|
||||||
|
==> qux
|
||||||
|
=> quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("escape custom bullet", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.Wrap(
|
||||||
|
textfmt.List(
|
||||||
|
textfmt.Item(textfmt.Text("foo bar baz"), textfmt.Bullet("\x00>")),
|
||||||
|
textfmt.Item(textfmt.Text("qux"), textfmt.Bullet("=>")),
|
||||||
|
textfmt.Item(textfmt.Text("quux"), textfmt.Bullet("=>")),
|
||||||
|
),
|
||||||
|
10,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Teletype(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
·> foo bar
|
||||||
|
baz
|
||||||
|
=> qux
|
||||||
|
=> quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
@ -1193,6 +1252,88 @@ one: foo bar
|
|||||||
baz
|
baz
|
||||||
two: qux
|
two: qux
|
||||||
three: quux
|
three: quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("varying length bullets", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.Wrap(
|
||||||
|
textfmt.DefinitionList(
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("one"),
|
||||||
|
textfmt.Text("foo bar baz"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("two"),
|
||||||
|
textfmt.Text("qux"),
|
||||||
|
textfmt.Bullet("==>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("three"),
|
||||||
|
textfmt.Text("quux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
18,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Teletype(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
=> one: foo bar
|
||||||
|
baz
|
||||||
|
==> two: qux
|
||||||
|
=> three: quux
|
||||||
|
`
|
||||||
|
|
||||||
|
if "\n"+b.String() != expect {
|
||||||
|
t.Fatal("\n" + b.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("escape custom bullet", func(t *testing.T) {
|
||||||
|
doc := textfmt.Doc(
|
||||||
|
textfmt.Wrap(
|
||||||
|
textfmt.DefinitionList(
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("one"),
|
||||||
|
textfmt.Text("foo bar baz"),
|
||||||
|
textfmt.Bullet("\x00>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("two"),
|
||||||
|
textfmt.Text("qux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
textfmt.Definition(
|
||||||
|
textfmt.Text("three"),
|
||||||
|
textfmt.Text("quux"),
|
||||||
|
textfmt.Bullet("=>"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
18,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
if err := textfmt.Teletype(&b, doc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const expect = `
|
||||||
|
·> one: foo bar
|
||||||
|
baz
|
||||||
|
=> two: qux
|
||||||
|
=> three: quux
|
||||||
`
|
`
|
||||||
|
|
||||||
if "\n"+b.String() != expect {
|
if "\n"+b.String() != expect {
|
||||||
|
|||||||
8
text.go
8
text.go
@ -60,11 +60,19 @@ func itemToParagraph(list Entry, itemText Txt, prefix ...string) Entry {
|
|||||||
|
|
||||||
var prefixLength int
|
var prefixLength int
|
||||||
for _, p := range prefix {
|
for _, p := range prefix {
|
||||||
|
if len(p) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
prefixLength += len([]rune(p)) + 1
|
prefixLength += len([]rune(p)) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefixText []Txt
|
var prefixText []Txt
|
||||||
for _, p := range prefix {
|
for _, p := range prefix {
|
||||||
|
if len(p) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
prefixText = append(prefixText, Text(p))
|
prefixText = append(prefixText, Text(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user