Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Gmail: clarify that `gmail drafts delete` permanently deletes drafts and cannot be recovered. (#656, #659) — thanks @chrischall.
- Sheets: add `--inherit-from-before` to `sheets insert` so callers can choose whether inserted rows/columns inherit formatting from the preceding or following neighbor. (#655, #658) — thanks @chrischall.
- Auth: update stored OAuth scope metadata from observed granted scopes during refresh so `auth list` reflects newly usable services. (#649)
- Docs: preserve paragraph-separating blank lines when replacing a single tab from Markdown. (#644)
- Docs: update the bundled `gog` agent skill to preserve broad user OAuth scopes during reauth and rely on command guards for scoped execution.

## 0.19.0 - 2026-05-22
Expand Down
7 changes: 7 additions & 0 deletions internal/cmd/docs_markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ func ParseMarkdown(text string) []MarkdownElement {

// Empty line
if strings.TrimSpace(line) == "" {
if len(elements) > 0 && elements[len(elements)-1].Type != MDEmptyLine {
elements = append(elements, MarkdownElement{Type: MDEmptyLine})
Comment on lines +109 to +110
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid doubling blank lines around native tables

When Markdown contains the usual blank line before or after a pipe table, this unconditional MDEmptyLine is emitted adjacent to MDTable. The table renderer already writes a placeholder newline for every table (docs_formatter.go:301-303), and the table inserter documents that Google Docs also inserts a newline before the table (docs_table_inserter.go:159-162), so inputs like Intro\n\n| A |...\n\nOutro now gain extra empty paragraphs around the native table rather than preserving the original spacing.

Useful? React with 👍 / 👎.

}
continue
}

Expand Down Expand Up @@ -205,6 +208,10 @@ func ParseMarkdown(text string) []MarkdownElement {
})
}

if len(elements) > 0 && elements[len(elements)-1].Type == MDEmptyLine {
elements = elements[:len(elements)-1]
}

return elements
}

Expand Down
7 changes: 6 additions & 1 deletion internal/cmd/docs_markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ func TestParseMarkdown(t *testing.T) {
{
name: "mixed content",
input: "# Title\n\nParagraph here\n\n- List item",
expected: []MarkdownElementType{MDHeading1, MDParagraph, MDListItem},
expected: []MarkdownElementType{MDHeading1, MDEmptyLine, MDParagraph, MDEmptyLine, MDListItem},
},
{
name: "consecutive blank lines collapse",
input: "Paragraph A\n\n\nParagraph B\n",
expected: []MarkdownElementType{MDParagraph, MDEmptyLine, MDParagraph},
},
}

Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/docs_write_markdown_tab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func TestDocsWrite_MarkdownReplaceWithTab(t *testing.T) {
if loc.TabId != "t.second" || loc.Index != 1 {
t.Fatalf("insert location = %+v, want {TabId:t.second Index:1}", loc)
}
if got := insertReqs[0].InsertText.Text; got != "Title\nbold\n" {
t.Fatalf("inserted text = %q, want %q", got, "Title\nbold\n")
if got := insertReqs[0].InsertText.Text; got != "Title\n\nbold\n" {
t.Fatalf("inserted text = %q, want %q", got, "Title\n\nbold\n")
}
for i, req := range insertReqs[1:] {
var r *docs.Range
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/docs_write_markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ func TestDocsWrite_MarkdownAppendUsesDocsFormatting(t *testing.T) {
if reqs[0].InsertText == nil {
t.Fatalf("expected first request to insert text, got %#v", reqs[0])
}
if got := reqs[0].InsertText; got.Location.Index != 9 || got.Text != "\nTitle\nbold\n" {
if got := reqs[0].InsertText; got.Location.Index != 9 || got.Text != "\nTitle\n\nbold\n" {
t.Fatalf("unexpected markdown insert: %#v", got)
}
if reqs[1].UpdateParagraphStyle == nil {
Expand All @@ -512,7 +512,7 @@ func TestDocsWrite_MarkdownAppendUsesDocsFormatting(t *testing.T) {
if reqs[2].UpdateTextStyle == nil {
t.Fatalf("expected bold text style request, got %#v", reqs[2])
}
if got := reqs[2].UpdateTextStyle.Range; got.StartIndex != 16 || got.EndIndex != 20 {
if got := reqs[2].UpdateTextStyle.Range; got.StartIndex != 17 || got.EndIndex != 21 {
t.Fatalf("unexpected bold range: %#v", got)
}
}
Expand Down Expand Up @@ -569,13 +569,13 @@ func TestDocsWrite_MarkdownAppendStartsStyledBlocksOnFreshParagraph(t *testing.T
if len(reqs) != 4 {
t.Fatalf("expected insert, bullet, code font, and code shading requests, got %#v", reqs)
}
if got := reqs[0].InsertText; got == nil || got.Location.Index != 9 || got.Text != "\nItem\nline 1"+docsSoftLineBreak+"line 2\n" {
if got := reqs[0].InsertText; got == nil || got.Location.Index != 9 || got.Text != "\nItem\n\nline 1"+docsSoftLineBreak+"line 2\n" {
t.Fatalf("unexpected markdown insert: %#v", got)
}
if got := reqs[1].CreateParagraphBullets; got == nil || got.Range.StartIndex != 10 || got.Range.EndIndex != 15 {
t.Fatalf("unexpected bullet request: %#v", got)
}
if got := reqs[3].UpdateParagraphStyle; got == nil || got.Range.StartIndex != 15 || got.Range.EndIndex != 29 {
if got := reqs[3].UpdateParagraphStyle; got == nil || got.Range.StartIndex != 16 || got.Range.EndIndex != 30 {
t.Fatalf("unexpected code shading request: %#v", got)
}
}
Expand Down
Loading