-
Notifications
You must be signed in to change notification settings - Fork 657
docs cat drops internal link targets on text runs (link.tabId / bookmarkId / headingId) in all output modes; readable only via --raw #921
Copy link
Copy link
Closed
Labels
P2Normal priority bug or improvement with limited blast radius.Normal priority bug or improvement with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.ClawSweeper found an open linked pull request for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.ClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.User-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.
Description
Metadata
Metadata
Assignees
Labels
P2Normal priority bug or improvement with limited blast radius.Normal priority bug or improvement with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.ClawSweeper found an open linked pull request for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.ClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.User-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.
Type
Fields
Priority
None yet
Summary
docs catrenders a text run that carries an internal link (TextRun.TextStyle.Link.TabId, and equivalently.BookmarkId/.HeadingId) as bare text, silently dropping the link target in every non---rawmode (default,--plain,--chips,--json). The destination is only recoverable from--raw.This is a follow-up in addition to #917 / #920. That work covers external URL links on text runs (
Link.Url). Internal links are a distinct, still-open case: #920 handlesLink.Urlonly and explicitly scopes out internal links, so this gap remains after it merges.Why this is a consistency gap, not a new feature
A rich-link smart chip that points at a document tab already renders as a deep link today:
But an ordinary text run pointing at the same tab via
Link.TabIdrenders as plain text with no target:Same destination, two authoring styles, two different outputs. The deep-link rendering the chip path already produces can be reused for internal text-run links.
Minimal repro (synthetic
documents.getshape)A document
DOC_IDwith two tabs,Overview(t.aaa) andDetails(t.bbb). A paragraph on the Overview tab contains one text-run internal link and one rich-link chip, both targetingt.bbb:{ "paragraph": { "elements": [ { "startIndex": 1, "endIndex": 12, "textRun": { "content": "See details", "textStyle": { "link": { "tabId": "t.bbb" } } } }, { "startIndex": 12, "endIndex": 13, "textRun": { "content": " " } }, { "startIndex": 13, "endIndex": 14, "richLink": { "richLinkProperties": { "title": "Details section", "uri": "https://docs.google.com/document/d/DOC_ID/edit?tab=t.bbb" } } }, { "startIndex": 14, "endIndex": 15, "textRun": { "content": "\n" } } ] } }Current output (
docs cat --chips, v0.34.0; unchanged by #920)The text-run link (
See details→t.bbb) is dropped; only the chip renders.Expected
(under the opt-in
--chipsrendered path, matching #920's behavior for external links; default/--plaintext unchanged).Root cause
internal/cmd/docs_read.go, functionappendDocsElementRenderedText(paragraph/text-run branch, ~L425–427 onmain) appendsp.TextRun.Contentwithout inspectingp.TextRun.TextStyle.Link. #920 adds aLink.Urlcheck here but notLink.TabId/Link.BookmarkId/Link.HeadingId. The deep-link markdown format is already constructed in the same file'srenderDocsSmartChip,case p.RichLink != nilblock (~L519–541), building[title](uri)fromRichLinkProperties.Uri.Proposed fix
Note that, unlike rich links (where the API supplies a full
Uri), internal links expose only an ID, so gog must synthesize the deep link from the document ID plus the id:Link.TabId: render[<text>](https://docs.google.com/document/d/<docId>/edit?tab=<tabId>), reusing the existing chip deep-link format. This is unambiguous and mirrors what the rich-link path already emits.Link.BookmarkId/Link.HeadingId: fuzzier (need anchor/heading resolution); can be handled separately or, at minimum, surfaced as structured metadata in--jsonso the target is not silently lost.Severity / notes
Lower priority than #917: this is not data loss — the
tabId(etc.) is present in--raw, and a tab id resolves to a tab already listed in the samedocuments.getresponse. It is a rendering-parity gap in the opt-in path, tractable with the format the codebase already has.