gogcli/internal/cmd/slides_replace_text.go
2026-04-28 01:18:26 +01:00

102 lines
2.7 KiB
Go

package cmd
import (
"context"
"fmt"
"os"
"strings"
"google.golang.org/api/slides/v1"
"github.com/steipete/gogcli/internal/outfmt"
"github.com/steipete/gogcli/internal/ui"
)
// SlidesReplaceTextCmd performs a find-and-replace across a presentation.
// It is a thin wrapper around presentations.batchUpdate with a single
// ReplaceAllTextRequest.
type SlidesReplaceTextCmd struct {
PresentationID string `arg:"" name:"presentationId" help:"Presentation ID"`
Find string `arg:"" name:"find" help:"Substring to find"`
Replacement string `arg:"" name:"replacement" help:"Replacement text"`
MatchCase bool `name:"match-case" help:"Case-sensitive match (default: false)"`
Pages []string `name:"page" help:"Restrict replacement to specific slide object IDs (repeatable)"`
}
// Run executes the replace-text command.
func (c *SlidesReplaceTextCmd) Run(ctx context.Context, flags *RootFlags) error {
u := ui.FromContext(ctx)
presentationID := strings.TrimSpace(c.PresentationID)
if presentationID == "" {
return usage("empty presentationId")
}
if c.Find == "" {
return usage("empty find text")
}
// Build the batchUpdate request body.
req := &slides.ReplaceAllTextRequest{
ContainsText: &slides.SubstringMatchCriteria{
Text: c.Find,
MatchCase: c.MatchCase,
},
ReplaceText: c.Replacement,
}
if len(c.Pages) > 0 {
// Preserve order and trim whitespace on each page id.
pages := make([]string, 0, len(c.Pages))
for _, p := range c.Pages {
p = strings.TrimSpace(p)
if p == "" {
return usage("empty page object ID")
}
pages = append(pages, p)
}
req.PageObjectIds = pages
}
body := &slides.BatchUpdatePresentationRequest{
Requests: []*slides.Request{{ReplaceAllText: req}},
}
// Dry-run: print the request body we would send and exit without calling the API.
if flags != nil && flags.DryRun {
return writeSlidesBatchUpdateDryRun(ctx, body)
}
account, err := requireAccount(flags)
if err != nil {
return err
}
slidesSvc, err := newSlidesService(ctx, account)
if err != nil {
return err
}
resp, err := slidesSvc.Presentations.BatchUpdate(presentationID, body).Context(ctx).Do()
if err != nil {
return fmt.Errorf("replace text: %w", err)
}
if outfmt.IsJSON(ctx) {
return outfmt.WriteJSON(ctx, os.Stdout, resp)
}
var replaced int64
if resp != nil {
for _, r := range resp.Replies {
if r != nil && r.ReplaceAllText != nil {
replaced += r.ReplaceAllText.OccurrencesChanged
}
}
}
revisionID := ""
if resp != nil && resp.WriteControl != nil {
revisionID = resp.WriteControl.RequiredRevisionId
}
u.Out().Printf("ok | revisionId=%s | replaced=%d", revisionID, replaced)
return nil
}