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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ go run ./cmd/gws # or go run .

## Current Version

**v1.7.0** - Full Slides API editing operations. Adds 12 new Slides commands: delete-object, delete-text, update-text-style, update-transform, create-table, insert-table-rows, delete-table-row, update-table-cell, update-table-border, update-paragraph-style, update-shape, reorder-slides. Enables complete programmatic control over presentation elements including tables, text styling, transforms, and slide ordering.
**v1.8.0** - Table cell text support. Adds `--table-id`, `--row`, and `--col` flags to `slides add-text` for populating table cells programmatically.

## Roadmap

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PKG := ./cmd/gws
BUILD_DIR := ./bin

# Version info
VERSION ?= 1.7.0
VERSION ?= 1.8.0
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
LDFLAGS := -ldflags "-X github.com/omriariav/workspace-cli/cmd.Version=$(VERSION) \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Add `--format text` to any command for human-readable output.
| `gws slides duplicate-slide <id>` | Duplicate slide (`--slide-id` or `--slide-number`) |
| `gws slides add-shape <id>` | Add shape (`--slide-id/--slide-number`, `--type`, `--x`, `--y`, `--width`, `--height`) |
| `gws slides add-image <id>` | Add image (`--slide-id/--slide-number`, `--url`, `--x`, `--y`, `--width`) |
| `gws slides add-text <id>` | Insert text into object (`--object-id`, `--text`, `--at`) |
| `gws slides add-text <id>` | Insert text into shape or table cell (`--object-id` or `--table-id`/`--row`/`--col`, `--text`, `--at`) |
| `gws slides replace-text <id>` | Find and replace text (`--find`, `--replace`, `--match-case`) |
| `gws slides delete-object <id>` | Delete any page element (`--object-id`) |
| `gws slides delete-text <id>` | Clear text from shape (`--object-id`, `--from`, `--to`) |
Expand Down
91 changes: 69 additions & 22 deletions cmd/slides.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,12 @@ Position and size are in points (PT). The image URL must be publicly accessible.
var slidesAddTextCmd = &cobra.Command{
Use: "add-text <presentation-id>",
Short: "Add text to an object",
Long: "Inserts text into an existing shape or text box on a slide.",
Args: cobra.ExactArgs(1),
RunE: runSlidesAddText,
Long: `Inserts text into an existing shape, text box, or table cell.

For shapes/text boxes, use --object-id.
For table cells, use --table-id with --row and --col (0-indexed).`,
Args: cobra.ExactArgs(1),
RunE: runSlidesAddText,
}

var slidesReplaceTextCmd = &cobra.Command{
Expand Down Expand Up @@ -287,10 +290,12 @@ func init() {
slidesAddImageCmd.MarkFlagRequired("url")

// Add-text flags
slidesAddTextCmd.Flags().String("object-id", "", "Object ID to insert text into (required)")
slidesAddTextCmd.Flags().String("object-id", "", "Object ID to insert text into (required for shapes/text boxes)")
slidesAddTextCmd.Flags().String("table-id", "", "Table object ID (required for table cells, mutually exclusive with --object-id)")
slidesAddTextCmd.Flags().Int("row", -1, "Row index, 0-based (required with --table-id)")
slidesAddTextCmd.Flags().Int("col", -1, "Column index, 0-based (required with --table-id)")
slidesAddTextCmd.Flags().String("text", "", "Text to insert (required)")
slidesAddTextCmd.Flags().Int("at", 0, "Position to insert at (0 = beginning)")
slidesAddTextCmd.MarkFlagRequired("object-id")
slidesAddTextCmd.MarkFlagRequired("text")

// Replace-text flags
Expand Down Expand Up @@ -1250,8 +1255,36 @@ func runSlidesAddImage(cmd *cobra.Command, args []string) error {

func runSlidesAddText(cmd *cobra.Command, args []string) error {
p := printer.New(os.Stdout, GetFormat())
ctx := context.Background()

// Parse flags first (before client creation for early validation)
presentationID := args[0]
objectID, _ := cmd.Flags().GetString("object-id")
tableID, _ := cmd.Flags().GetString("table-id")
row, _ := cmd.Flags().GetInt("row")
col, _ := cmd.Flags().GetInt("col")
text, _ := cmd.Flags().GetString("text")
insertionIndex, _ := cmd.Flags().GetInt("at")

// Validate mutually exclusive flags (fail fast before network calls)
if objectID != "" && tableID != "" {
return p.PrintError(fmt.Errorf("cannot specify both --object-id and --table-id"))
}
if objectID == "" && tableID == "" {
return p.PrintError(fmt.Errorf("must specify either --object-id or --table-id"))
}

// Validate table cell mode requires row and col
if tableID != "" {
if row < 0 {
return p.PrintError(fmt.Errorf("--row is required when using --table-id (valid values: 0 or greater)"))
}
if col < 0 {
return p.PrintError(fmt.Errorf("--col is required when using --table-id (valid values: 0 or greater)"))
}
}

// Now create the client after validation passes
ctx := context.Background()
factory, err := client.NewFactory(ctx)
if err != nil {
return p.PrintError(err)
Expand All @@ -1262,18 +1295,38 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
return p.PrintError(err)
}

presentationID := args[0]
objectID, _ := cmd.Flags().GetString("object-id")
text, _ := cmd.Flags().GetString("text")
insertionIndex, _ := cmd.Flags().GetInt("at")
// Build the InsertText request
insertTextReq := &slides.InsertTextRequest{
Text: text,
InsertionIndex: int64(insertionIndex),
}

result := map[string]interface{}{
"status": "inserted",
"presentation_id": presentationID,
"text_length": len(text),
"position": insertionIndex,
}

if tableID != "" {
// Table cell mode
insertTextReq.ObjectId = tableID
insertTextReq.CellLocation = &slides.TableCellLocation{
RowIndex: int64(row),
ColumnIndex: int64(col),
}
result["table_id"] = tableID
result["row"] = row
result["col"] = col
} else {
// Shape/text box mode
insertTextReq.ObjectId = objectID
result["object_id"] = objectID
}

requests := []*slides.Request{
{
InsertText: &slides.InsertTextRequest{
ObjectId: objectID,
Text: text,
InsertionIndex: int64(insertionIndex),
},
InsertText: insertTextReq,
},
}

Expand All @@ -1284,13 +1337,7 @@ func runSlidesAddText(cmd *cobra.Command, args []string) error {
return p.PrintError(fmt.Errorf("failed to add text: %w", err))
}

return p.Print(map[string]interface{}{
"status": "inserted",
"presentation_id": presentationID,
"object_id": objectID,
"text_length": len(text),
"position": insertionIndex,
})
return p.Print(result)
}

func runSlidesReplaceText(cmd *cobra.Command, args []string) error {
Expand Down
Loading