Repository navigation
Description
Bug
When conceal is true (the default for MarkdownRenderable), bare URLs in markdown content render as https://example.com (https://example.com) — the URL text followed by the same URL in parentheses.
This happens because the link case in renderInlineToken unconditionally appends (href) after the link label. For named links like [click here](https://example.com), this renders correctly as click here (https://example.com). But for bare/autolinked URLs, the link text is the href, producing duplication.
Location
packages/core/src/renderables/Markdown.ts — the "link" case in renderInlineToken:
case "link": {
const linkHref = { url: token.href }
if (this._conceal) {
for (const child of token.tokens) {
this.renderInlineTokenWithStyle(child, chunks, "markup.link.label", linkHref)
}
// Always appends (href), even when link text === href
chunks.push(this.createChunk(" (", "markup.link", linkHref))
chunks.push(this.createChunk(token.href, "markup.link.url", linkHref))
chunks.push(this.createChunk(")", "markup.link", linkHref))
}
}Fix
Skip the (href) suffix when the link text equals the href:
case "link": {
const linkHref = { url: token.href }
if (this._conceal) {
const linkText = token.tokens.map(t => t.raw).join("")
const isBareUrl = linkText === token.href
for (const child of token.tokens) {
this.renderInlineTokenWithStyle(child, chunks, "markup.link.label", linkHref)
}
if (!isBareUrl) {
chunks.push(this.createChunk(" (", "markup.link", linkHref))
chunks.push(this.createChunk(token.href, "markup.link.url", linkHref))
chunks.push(this.createChunk(")", "markup.link", linkHref))
}
}
}Reproduction
Any markdown with a bare URL:
Check https://github.com/anomalyco/opentui for details.Renders as: Check https://github.com/anomalyco/opentui (https://github.com/anomalyco/opentui) for details.
Expected: Check https://github.com/anomalyco/opentui for details.
This also affects markdown tables where bare URLs are common — the duplication wastes column width and degrades readability.
Affected version
@opentui/core 0.2.6 (and likely since 0.1.88 when conceal was introduced via #767)
Related
- Long URLs in markdown tables are split across lines and become unclickable opencode#18394 — long URLs in tables split/unclickable (separate but related rendering issue)
Activity
ash543210 commentedon May 30, 2026
I'd like to help with this, but I noticed #1081 already implemented the
token.text === token.hreffix and was closed without merging. Before opening another PR I'd rather understand the preferred direction:detectLinkslayer rather than in thelinkconceal branch)?Happy to implement whichever you'd prefer. Thanks!
epicwhale commentedon Jun 26, 2026
I face this issue all the time and it would be good to have better usability around how links are shown, made clickable, and reduced duplication/noise in the TUI output