diff --git a/CHANGELOG.md b/CHANGELOG.md index f05a4d31..1ffa692e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Gmail: keep label IDs case-sensitive during label resolution and duplicate-name checks while still matching label names case-insensitively. - 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. - 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 diff --git a/docs/commands/gog-sheets-insert.md b/docs/commands/gog-sheets-insert.md index abbd4803..6aeb302d 100644 --- a/docs/commands/gog-sheets-insert.md +++ b/docs/commands/gog-sheets-insert.md @@ -31,6 +31,7 @@ gog sheets (sheet) insert [flags] | `--gmail-no-send` | `bool` | false | Block Gmail send operations (agent safety) | | `-h`
`--help` | `kong.helpFlag` | | Show context-sensitive help. | | `--home` | `string` | | Override gogcli config/data/state/cache root (equivalent to GOG_HOME) | +| `--inherit-from-before` | `*bool` | | Inherit number format / styling from the row/column before the insertion. Defaults to true with --after, false otherwise; false inherits from the row/column after the insertion. | | `-j`
`--json`
`--machine` | `bool` | false | Output JSON to stdout (best for scripting) | | `--no-input`
`--non-interactive`
`--noninteractive` | `bool` | | Never prompt; fail instead (useful for CI) | | `-p`
`--plain`
`--tsv` | `bool` | false | Output stable, parseable text to stdout (TSV; no colors) | diff --git a/internal/cmd/sheets_insert.go b/internal/cmd/sheets_insert.go index 33590036..3149b5b3 100644 --- a/internal/cmd/sheets_insert.go +++ b/internal/cmd/sheets_insert.go @@ -18,6 +18,9 @@ type SheetsInsertCmd struct { Start int64 `arg:"" name:"start" help:"Position before which to insert (1-based; for cols 1=A, 2=B)"` Count int64 `name:"count" help:"Number of rows/columns to insert" default:"1"` After bool `name:"after" help:"Insert after the position instead of before"` + // *bool so an unset flag keeps the historical default (inherit only when + // --after); passing --inherit-from-before[=false] overrides it explicitly. + InheritFromBefore *bool `name:"inherit-from-before" help:"Inherit number format / styling from the row/column before the insertion. Defaults to true with --after, false otherwise; false inherits from the row/column after the insertion."` } func (c *SheetsInsertCmd) Run(ctx context.Context, flags *RootFlags) error { @@ -58,7 +61,15 @@ func (c *SheetsInsertCmd) Run(ctx context.Context, flags *RootFlags) error { startIndex = c.Start } endIndex := startIndex + c.Count + // Default: inherit formatting only when inserting after an existing line. + // An explicit --inherit-from-before[=false] overrides that default. inheritFromBefore := c.After + if c.InheritFromBefore != nil { + inheritFromBefore = *c.InheritFromBefore + } + if inheritFromBefore && startIndex == 0 { + return usagef("cannot inherit from the previous %s when inserting at position 1", dimLabel) + } if dryRunErr := dryRunExit(ctx, flags, "sheets.insert", map[string]any{ "spreadsheet_id": spreadsheetID, diff --git a/internal/cmd/sheets_insert_test.go b/internal/cmd/sheets_insert_test.go index a6db6971..f1758816 100644 --- a/internal/cmd/sheets_insert_test.go +++ b/internal/cmd/sheets_insert_test.go @@ -124,6 +124,58 @@ func TestSheetsInsertCmd(t *testing.T) { } }) + t.Run("insert after inheriting from following dimension", func(t *testing.T) { + gotInsert = nil + cmd := &SheetsInsertCmd{} + if err := runKong(t, cmd, []string{ + "s1", "Data", "rows", "2", "--count", "1", "--after", "--inherit-from-before=false", + }, ctx, flags); err != nil { + t.Fatalf("insert rows: %v", err) + } + if gotInsert == nil { + t.Fatal("expected insertDimension request") + } + // --after would default inheritFromBefore=true; the explicit flag overrides it + // so the API inherits from the following adjacent row/column instead. + if gotInsert.InheritFromBefore { + t.Fatal("expected inheritFromBefore=false when --inherit-from-before=false overrides --after") + } + }) + + t.Run("insert before with explicit inherit", func(t *testing.T) { + gotInsert = nil + cmd := &SheetsInsertCmd{} + if err := runKong(t, cmd, []string{ + "s1", "Data", "rows", "2", "--count", "1", "--inherit-from-before", + }, ctx, flags); err != nil { + t.Fatalf("insert rows: %v", err) + } + if gotInsert == nil { + t.Fatal("expected insertDimension request") + } + // before-insert defaults inheritFromBefore=false; the explicit flag overrides it. + if !gotInsert.InheritFromBefore { + t.Fatal("expected inheritFromBefore=true when --inherit-from-before is set") + } + }) + + t.Run("reject inherit from before at first row", func(t *testing.T) { + gotInsert = nil + cmd := &SheetsInsertCmd{} + err := runKong(t, cmd, []string{ + "s1", "Data", "rows", "1", "--inherit-from-before", + }, ctx, flags) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "cannot inherit from the previous row") { + t.Fatalf("unexpected error: %v", err) + } + if gotInsert != nil { + t.Fatal("did not expect API request") + } + }) + t.Run("insert cols before", func(t *testing.T) { gotInsert = nil cmd := &SheetsInsertCmd{}