Add insert command

This commit is contained in:
Rogee
2025-10-30 15:15:16 +08:00
parent 6a353b5086
commit a0d7084c28
35 changed files with 2044 additions and 37 deletions

90
cmd/insert.go Normal file
View File

@@ -0,0 +1,90 @@
package cmd
import (
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/rogeecn/renamer/internal/insert"
"github.com/rogeecn/renamer/internal/listing"
)
func newInsertCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "insert <position> <text>",
Short: "Insert text into filenames at specified positions",
Long: `Insert a Unicode string into each candidate filename at a specific position.
Supported positions: "^" (start), "$" (before extension), positive indexes (1-based),
negative indexes counting back from the end.`,
Args: cobra.MinimumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
scope, err := listing.ScopeFromCmd(cmd)
if err != nil {
return err
}
req := insert.NewRequest(scope)
dryRun, err := getBool(cmd, "dry-run")
if err != nil {
return err
}
autoApply, err := getBool(cmd, "yes")
if err != nil {
return err
}
if dryRun && autoApply {
return errors.New("--dry-run cannot be combined with --yes; remove one of them")
}
req.SetExecutionMode(dryRun, autoApply)
positionToken := args[0]
insertText := strings.Join(args[1:], " ")
req.SetPositionAndText(positionToken, insertText)
summary, planned, err := insert.Preview(cmd.Context(), req, cmd.OutOrStdout())
if err != nil {
return err
}
if summary.HasConflicts() {
return errors.New("conflicts detected; resolve them before applying")
}
if dryRun || !autoApply {
if !autoApply {
fmt.Fprintln(cmd.OutOrStdout(), "Preview complete. Re-run with --yes to apply.")
}
return nil
}
if len(planned) == 0 {
if summary.TotalCandidates == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "No candidates found.")
} else {
fmt.Fprintln(cmd.OutOrStdout(), "Nothing to apply; files already reflect requested insert.")
}
return nil
}
entry, err := insert.Apply(cmd.Context(), req, planned, summary)
if err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(), "Applied %d insert updates. Ledger updated.\n", len(entry.Operations))
return nil
},
}
cmd.Example = ` renamer insert ^ "[2025] " --dry-run
renamer insert -1 _FINAL --yes --path ./reports`
return cmd
}
func init() {
rootCmd.AddCommand(newInsertCommand())
}

View File

@@ -48,6 +48,7 @@ func NewRootCommand() *cobra.Command {
cmd.AddCommand(NewReplaceCommand())
cmd.AddCommand(NewRemoveCommand())
cmd.AddCommand(NewExtensionCommand())
cmd.AddCommand(newInsertCommand())
cmd.AddCommand(newUndoCommand())
return cmd

View File

@@ -29,12 +29,25 @@ func newUndoCommand() *cobra.Command {
out := cmd.OutOrStdout()
fmt.Fprintf(out, "Undo applied: %d operations reversed\n", len(entry.Operations))
if entry.Command == "extension" && entry.Metadata != nil {
if target, ok := entry.Metadata["targetExtension"].(string); ok && target != "" {
fmt.Fprintf(out, "Restored extensions to %s\n", target)
}
if sources, ok := entry.Metadata["sourceExtensions"].([]string); ok && len(sources) > 0 {
fmt.Fprintf(out, "Previous sources: %s\n", strings.Join(sources, ", "))
if entry.Metadata != nil {
switch entry.Command {
case "extension":
if target, ok := entry.Metadata["targetExtension"].(string); ok && target != "" {
fmt.Fprintf(out, "Restored extensions to %s\n", target)
}
if sources, ok := entry.Metadata["sourceExtensions"].([]string); ok && len(sources) > 0 {
fmt.Fprintf(out, "Previous sources: %s\n", strings.Join(sources, ", "))
}
case "insert":
insertText, _ := entry.Metadata["insertText"].(string)
positionToken, _ := entry.Metadata["positionToken"].(string)
if insertText != "" {
if positionToken != "" {
fmt.Fprintf(out, "Inserted text %q removed from position %s\n", insertText, positionToken)
} else {
fmt.Fprintf(out, "Inserted text %q removed\n", insertText)
}
}
}
}