Skip to content

Commit 42f47a2

Browse files
committed
feat(table): prefix all links with the position in the footer
1 parent 61cfc45 commit 42f47a2

19 files changed

+220
-256
lines changed

ansi/elements.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,7 @@ func (tr *ANSIRenderer) NewElement(node ast.Node, source []byte) Element {
226226
content, err := nodeContent(node, source)
227227

228228
if isFooterLinks && err == nil {
229-
text := string(content)
230-
tl := tableLink{content: text, href: string(n.Destination), title: string(n.Title)}
231-
text = linkWithSuffix(tl, ctx.table.groupedLinks)
232-
233-
children = []ElementRenderer{&BaseElement{Token: text}}
229+
children = []ElementRenderer{&BaseElement{Token: string(content)}}
234230
} else {
235231
nn := n.FirstChild()
236232
for nn != nil {
@@ -270,11 +266,8 @@ func (tr *ANSIRenderer) NewElement(node ast.Node, source []byte) Element {
270266
var renderer ElementRenderer
271267
if isFooterLinks {
272268
domain := linkDomain(u)
273-
tl := tableLink{content: domain, href: u}
274-
text := linkWithSuffix(tl, ctx.table.groupedAutoLinks)
275-
276269
renderer = &LinkElement{
277-
Children: []ElementRenderer{&BaseElement{Token: text}},
270+
Children: []ElementRenderer{&BaseElement{Token: domain}},
278271
URL: u,
279272
SkipHref: true,
280273
}
@@ -295,8 +288,6 @@ func (tr *ANSIRenderer) NewElement(node ast.Node, source []byte) Element {
295288

296289
if isFooterLinks && text == "" {
297290
text = linkDomain(string(n.Destination))
298-
tl := tableLink{content: text, href: string(n.Destination)}
299-
text = linkWithSuffix(tl, ctx.table.groupedImages)
300291
}
301292

302293
return Element{

ansi/table.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@ type TableElement struct {
1919
row []string
2020
source []byte
2121

22-
tableAutoLinks []tableLink
23-
tableImages []tableLink
24-
tableLinks []tableLink
22+
tableImages []tableLink
23+
tableLinks []tableLink
2524

26-
groupedAutoLinks groupedTableLinks
27-
groupedImages groupedTableLinks
28-
groupedLinks groupedTableLinks
25+
groupedImages groupedTableLinks
26+
groupedLinks groupedTableLinks
2927
}
3028

3129
// A TableRowElement is used to render a single row in a table.
@@ -127,10 +125,8 @@ func (e *TableElement) setBorders(ctx RenderContext) {
127125
func (e *TableElement) Finish(_ io.Writer, ctx RenderContext) error {
128126
defer func() {
129127
ctx.table.lipgloss = nil
130-
ctx.table.tableAutoLinks = nil
131128
ctx.table.tableImages = nil
132129
ctx.table.tableLinks = nil
133-
ctx.table.groupedAutoLinks = nil
134130
ctx.table.groupedImages = nil
135131
ctx.table.groupedLinks = nil
136132
}()

ansi/table_links.go

Lines changed: 38 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package ansi
33
import (
44
"bytes"
55
"fmt"
6+
"io"
67
"net/url"
7-
"slices"
88

99
xansi "github.com/charmbracelet/x/ansi"
1010
"github.com/charmbracelet/x/exp/slice"
@@ -13,9 +13,10 @@ import (
1313
)
1414

1515
type tableLink struct {
16-
href string
17-
title string
18-
content string
16+
href string
17+
title string
18+
content string
19+
linkType linkType
1920
}
2021

2122
type groupedTableLinks map[string][]tableLink
@@ -37,36 +38,35 @@ func (e *TableElement) printTableLinks(ctx RenderContext) {
3738
w := ctx.blockStack.Current().Block
3839
termWidth := int(ctx.blockStack.Width(ctx)) //nolint: gosec
3940

40-
renderLinkText := func(link tableLink, linkType linkType) string {
41+
renderLinkText := func(link tableLink, position int) string {
42+
var token string
4143
style := ctx.options.Styles.LinkText
4244

43-
var token string
44-
switch linkType {
45-
case linkTypeAuto:
46-
token = linkWithSuffix(link, ctx.table.groupedAutoLinks)
45+
switch link.linkType {
46+
case linkTypeAuto, linkTypeRegular:
47+
token = fmt.Sprintf("[%d]: %s", position, link.content)
4748
case linkTypeImage:
48-
token = linkWithSuffix(link, ctx.table.groupedImages)
49+
token = link.content
4950
style = ctx.options.Styles.ImageText
50-
case linkTypeRegular:
51-
token = linkWithSuffix(link, ctx.table.groupedLinks)
51+
style.Prefix = fmt.Sprintf("[%d]: %s", position, style.Prefix)
5252
}
5353

54+
var b bytes.Buffer
5455
el := &BaseElement{Token: token, Style: style}
55-
_ = el.Render(w, ctx)
56-
57-
return token
56+
_ = el.Render(io.MultiWriter(w, &b), ctx)
57+
return b.String()
5858
}
5959

60-
renderLinkHref := func(link tableLink, linkType linkType, linkText string) {
60+
renderLinkHref := func(link tableLink, linkText string) {
6161
style := ctx.options.Styles.Link
62-
if linkType == linkTypeImage {
62+
if link.linkType == linkTypeImage {
6363
style = ctx.options.Styles.Image
6464
}
6565

6666
// XXX(@andreynering): Once #411 is merged, use the hyperlink
6767
// protocol to make the link work for the full URL even if we
6868
// show it truncated.
69-
linkMaxWidth := max(termWidth-len(linkText)-1, 0)
69+
linkMaxWidth := max(termWidth-xansi.StringWidth(linkText)-1, 0)
7070
token := xansi.Truncate(link.href, linkMaxWidth, "…")
7171

7272
el := &BaseElement{Token: token, Style: style}
@@ -77,45 +77,38 @@ func (e *TableElement) printTableLinks(ctx RenderContext) {
7777
renderText(w, ctx.options.ColorProfile, ctx.blockStack.Current().Style.StylePrimitive, str)
7878
}
7979

80-
if len(ctx.table.tableAutoLinks) > 0 || len(ctx.table.tableLinks) > 0 {
80+
if len(ctx.table.tableLinks) > 0 {
8181
renderString("\n")
8282
}
83-
for _, link := range ctx.table.tableAutoLinks {
83+
for i, link := range ctx.table.tableLinks {
8484
renderString("\n")
85-
linkText := renderLinkText(link, linkTypeAuto)
85+
linkText := renderLinkText(link, i+1)
8686
renderString(" ")
87-
renderLinkHref(link, linkTypeAuto, linkText)
88-
}
89-
for _, link := range ctx.table.tableLinks {
90-
renderString("\n")
91-
linkText := renderLinkText(link, linkTypeRegular)
92-
renderString(" ")
93-
renderLinkHref(link, linkTypeRegular, linkText)
87+
renderLinkHref(link, linkText)
9488
}
9589

9690
if len(ctx.table.tableImages) > 0 {
9791
renderString("\n")
9892
}
99-
for _, image := range ctx.table.tableImages {
93+
for i, image := range ctx.table.tableImages {
10094
renderString("\n")
101-
linkText := renderLinkText(image, linkTypeImage)
95+
linkText := renderLinkText(image, i+1)
10296
renderString(" ")
103-
renderLinkHref(image, linkTypeImage, linkText)
97+
renderLinkHref(image, linkText)
10498
}
10599
}
106100

107101
func (e *TableElement) shouldPrintTableLinks(ctx RenderContext) bool {
108102
if ctx.options.InlineTableLinks {
109103
return false
110104
}
111-
if len(ctx.table.tableAutoLinks) == 0 && len(ctx.table.tableLinks) == 0 && len(ctx.table.tableImages) == 0 {
105+
if len(ctx.table.tableLinks) == 0 && len(ctx.table.tableImages) == 0 {
112106
return false
113107
}
114108
return true
115109
}
116110

117111
func (e *TableElement) collectLinksAndImages(ctx RenderContext) error {
118-
autoLinks := make([]tableLink, 0)
119112
images := make([]tableLink, 0)
120113
links := make([]tableLink, 0)
121114

@@ -128,19 +121,21 @@ func (e *TableElement) collectLinksAndImages(ctx RenderContext) error {
128121
case *ast.AutoLink:
129122
uri := string(n.URL(e.source))
130123
autoLink := tableLink{
131-
href: uri,
132-
content: linkDomain(uri),
124+
href: uri,
125+
content: linkDomain(uri),
126+
linkType: linkTypeAuto,
133127
}
134-
autoLinks = append(autoLinks, autoLink)
128+
links = append(links, autoLink)
135129
case *ast.Image:
136130
content, err := nodeContent(node, e.source)
137131
if err != nil {
138132
return ast.WalkStop, err
139133
}
140134
image := tableLink{
141-
href: string(n.Destination),
142-
title: string(n.Title),
143-
content: string(content),
135+
href: string(n.Destination),
136+
title: string(n.Title),
137+
content: string(content),
138+
linkType: linkTypeImage,
144139
}
145140
if image.content == "" {
146141
image.content = linkDomain(image.href)
@@ -152,9 +147,10 @@ func (e *TableElement) collectLinksAndImages(ctx RenderContext) error {
152147
return ast.WalkStop, err
153148
}
154149
link := tableLink{
155-
href: string(n.Destination),
156-
title: string(n.Title),
157-
content: string(content),
150+
href: string(n.Destination),
151+
title: string(n.Title),
152+
content: string(content),
153+
linkType: linkTypeRegular,
158154
}
159155
links = append(links, link)
160156
}
@@ -165,7 +161,6 @@ func (e *TableElement) collectLinksAndImages(ctx RenderContext) error {
165161
return fmt.Errorf("glamour: error collecting links: %w", err)
166162
}
167163

168-
ctx.table.tableAutoLinks = autoLinks
169164
ctx.table.tableImages = images
170165
ctx.table.tableLinks = links
171166
return nil
@@ -174,10 +169,6 @@ func (e *TableElement) collectLinksAndImages(ctx RenderContext) error {
174169
func (e *TableElement) uniqAndGroupLinks(ctx RenderContext) {
175170
groupByContentFunc := func(l tableLink) string { return l.content }
176171

177-
// auto links
178-
ctx.table.tableAutoLinks = slice.Uniq(ctx.table.tableAutoLinks)
179-
ctx.table.groupedAutoLinks = slice.GroupBy(ctx.table.tableAutoLinks, groupByContentFunc)
180-
181172
// images
182173
ctx.table.tableImages = slice.Uniq(ctx.table.tableImages)
183174
ctx.table.groupedImages = slice.GroupBy(ctx.table.tableImages, groupByContentFunc)
@@ -232,12 +223,3 @@ func linkDomain(href string) string {
232223
}
233224
return "link"
234225
}
235-
236-
func linkWithSuffix(tl tableLink, grouped groupedTableLinks) string {
237-
token := tl.content
238-
if len(grouped[token]) < 2 {
239-
return token
240-
}
241-
index := slices.Index(grouped[token], tl)
242-
return fmt.Sprintf("%s[%d]", token, index+1)
243-
}

ansi/testdata/TestRenderer/table.golden

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ansi/testdata/TestRenderer/table_align.golden

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ansi/testdata/TestRenderer/table_with_footer_auto_links.golden

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ansi/testdata/TestRenderer/table_with_footer_images.golden

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)