Skip to content

Commit 468e9f8

Browse files
committed
feat(docs): add tab-aware raw output
1 parent ebc8218 commit 468e9f8

6 files changed

Lines changed: 301 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Gmail: report attached filenames and byte sizes in JSON results for send and draft create/update. (#716) — thanks @chrischall.
88
- Gmail: add `gmail watch pull` for Pub/Sub pull subscription consumers with hook retry support. (#700) — thanks @joshp123.
9+
- Docs: add `--tab` and `--all-tabs` to `docs raw` for inspecting specific or complete multi-tab document content. (#697) — thanks @sebsnyk.
910

1011
### Fixed
1112

docs/commands/gog-docs-raw.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ gog docs (doc) raw <docId> [flags]
2020
| --- | --- | --- | --- |
2121
| `--access-token` | `string` | | Use provided access token directly (bypasses stored refresh tokens; token expires in ~1h) |
2222
| `-a`<br>`--account`<br>`--acct` | `string` | | Account email for API commands (gmail/calendar/chat/classroom/drive/drivelabels/docs/slides/contacts/tasks/people/sheets/forms/sites/appscript/analytics/searchconsole/youtube/photos) |
23+
| `--all-tabs` | `bool` | | Return the canonical Document response with all tab content populated |
2324
| `--client` | `string` | | OAuth client name (selects stored credentials + token bucket) |
2425
| `--color` | `string` | auto | Color output: auto\|always\|never |
2526
| `--disable-commands` | `string` | | Comma-separated list of disabled commands; dot paths allowed |
@@ -36,6 +37,7 @@ gog docs (doc) raw <docId> [flags]
3637
| `--pretty` | `bool` | | Pretty-print JSON (default: compact single-line) |
3738
| `--results-only` | `bool` | | In JSON mode, emit only the primary result (drops envelope fields like nextPageToken) |
3839
| `--select`<br>`--pick`<br>`--project` | `string` | | In JSON mode, select comma-separated fields (best-effort; supports dot paths). Desire path: use --fields for most commands. |
40+
| `--tab` | `string` | | Return one tab by title or ID in the legacy top-level Document shape |
3941
| `-v`<br>`--verbose` | `bool` | | Enable verbose logging |
4042
| `--version` | `kong.VersionFlag` | | Print version and exit |
4143
| `--wrap-untrusted` | `bool` | false | In JSON/raw output, wrap fetched text fields in external untrusted-content markers |

docs/docs-editing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ Use raw output when a script needs the Google Docs API object:
201201

202202
```bash
203203
gog docs raw <docId> --pretty
204+
gog docs raw <docId> --tab "Notes" --pretty
205+
gog docs raw <docId> --all-tabs --json
204206
```
205207

208+
`--tab` returns one tab in the same top-level Document shape used by the
209+
default response. `--all-tabs` returns the canonical recursive `tabs` tree.
210+
206211
See [Raw API Dumps](raw-api.md) for lossless-output safety notes.

docs/raw-api.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,18 @@ returns it.
2828
```bash
2929
gog drive raw <fileId> --pretty
3030
gog docs raw <docId> --json > doc-api.json
31+
gog docs raw <docId> --tab "Notes" --pretty
32+
gog docs raw <docId> --all-tabs --json > doc-tabs-api.json
3133
gog gmail raw <messageId> --format metadata --json
3234
gog sheets raw <spreadsheetId> --include-grid-data --json
3335
```
3436

37+
`gog docs raw --tab` resolves a tab title or ID and projects that tab into the
38+
legacy top-level `Document` fields such as `body`, `lists`, and
39+
`inlineObjects`. `--all-tabs` keeps the canonical `Documents.Get` response and
40+
populates its recursive `tabs` tree. Without either flag, the command keeps the
41+
existing first-tab response.
42+
3543
Use service-native field masks when available:
3644

3745
```bash

internal/cmd/docs.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"strings"
99

10+
"google.golang.org/api/docs/v1"
1011
"google.golang.org/api/drive/v3"
1112
gapi "google.golang.org/api/googleapi"
1213

@@ -68,22 +69,31 @@ type DocsTabsCmd struct {
6869
// REST reference: https://developers.google.com/docs/api/reference/rest/v1/documents/get
6970
// Go type: https://pkg.go.dev/google.golang.org/api/docs/v1#Document
7071
type DocsRawCmd struct {
71-
DocID string `arg:"" name:"docId" help:"Doc ID"`
72-
Pretty bool `name:"pretty" help:"Pretty-print JSON (default: compact single-line)"`
72+
DocID string `arg:"" name:"docId" help:"Doc ID"`
73+
Pretty bool `name:"pretty" help:"Pretty-print JSON (default: compact single-line)"`
74+
Tab string `name:"tab" help:"Return one tab by title or ID in the legacy top-level Document shape"`
75+
AllTabs bool `name:"all-tabs" help:"Return the canonical Document response with all tab content populated"`
7376
}
7477

7578
func (c *DocsRawCmd) Run(ctx context.Context, flags *RootFlags) error {
7679
id := strings.TrimSpace(c.DocID)
7780
if id == "" {
7881
return usage("empty docId")
7982
}
83+
if strings.TrimSpace(c.Tab) != "" && c.AllTabs {
84+
return usage("--tab and --all-tabs cannot be used together")
85+
}
8086

8187
svc, err := requireDocsService(ctx, flags)
8288
if err != nil {
8389
return err
8490
}
8591

86-
doc, err := svc.Documents.Get(id).Context(ctx).Do()
92+
getCall := svc.Documents.Get(id).Context(ctx)
93+
if strings.TrimSpace(c.Tab) != "" || c.AllTabs {
94+
getCall = getCall.IncludeTabsContent(true)
95+
}
96+
doc, err := getCall.Do()
8797
if err != nil {
8898
if isDocsNotFound(err) {
8999
return fmt.Errorf("doc not found or not a Google Doc (id=%s)", id)
@@ -95,9 +105,46 @@ func (c *DocsRawCmd) Run(ctx context.Context, flags *RootFlags) error {
95105
return err
96106
}
97107

108+
if strings.TrimSpace(c.Tab) != "" {
109+
tab, tabErr := findTab(flattenTabs(doc.Tabs), c.Tab)
110+
if tabErr != nil {
111+
return tabErr
112+
}
113+
doc, err = projectRawDocumentTab(doc, tab)
114+
if err != nil {
115+
return err
116+
}
117+
}
118+
98119
return writeRawJSON(ctx, doc, c.Pretty)
99120
}
100121

122+
func projectRawDocumentTab(doc *docs.Document, tab *docs.Tab) (*docs.Document, error) {
123+
if tab == nil || tab.DocumentTab == nil {
124+
return nil, errors.New("selected tab has no document content")
125+
}
126+
127+
content := tab.DocumentTab
128+
return &docs.Document{
129+
Body: content.Body,
130+
DocumentId: doc.DocumentId,
131+
DocumentStyle: content.DocumentStyle,
132+
Footers: content.Footers,
133+
Footnotes: content.Footnotes,
134+
Headers: content.Headers,
135+
InlineObjects: content.InlineObjects,
136+
Lists: content.Lists,
137+
NamedRanges: content.NamedRanges,
138+
NamedStyles: content.NamedStyles,
139+
PositionedObjects: content.PositionedObjects,
140+
RevisionId: doc.RevisionId,
141+
SuggestedDocumentStyleChanges: content.SuggestedDocumentStyleChanges,
142+
SuggestedNamedStylesChanges: content.SuggestedNamedStylesChanges,
143+
SuggestionsViewMode: doc.SuggestionsViewMode,
144+
Title: doc.Title,
145+
}, nil
146+
}
147+
101148
type DocsExportCmd struct {
102149
DocID string `arg:"" name:"docId" help:"Doc ID"`
103150
Output OutputPathFlag `embed:""`

0 commit comments

Comments
 (0)