package mv import ( "errors" "fmt" "log" "os" "strings" "github.com/brtholomy/um/go/cat" "github.com/brtholomy/um/go/cmd" "github.com/brtholomy/um/go/flags" "github.com/brtholomy/um/go/next" "github.com/brtholomy/um/go/pipe" ) const ( CMD = cmd.Mv SUMMARY = "rename an um file descriptor field while updating its header" ) type options struct { Filename flags.Arg Descriptor flags.Arg Help flags.Bool } func initOpts() options { return options{ flags.Arg{"", "old filename"}, flags.Arg{"", "new descriptor"}, flags.Bool{"--help", "-h", false, "show help"}, } } // generates new filename and its content with updated H1 header func newNameAndContent(olds string, opts options) (name string, content string, err error) { // name and title num, err := next.NumFromLast(opts.Filename.Val) if err != nil { return "", "", err } name = fmt.Sprintf("%s.%s.md", num, opts.Descriptor.Val) title := fmt.Sprintf("# %s", name) // content head, tail, ok := strings.Cut(olds, pipe.Newline) // the file has no newline at all? if !ok { tail = head } // there was no title in the original if !strings.HasPrefix(head, cat.H1) { tail = olds } return name, fmt.Sprintf("%s%s%s", title, pipe.Newline, tail), nil } // effectively does a mv to the new filename, while updating the H1 header to match. func mv(opts options) error { oldb, err := os.ReadFile(opts.Filename.Val) if err != nil { return err } olds := string(oldb) name, content, err := newNameAndContent(olds, opts) if err != nil { return err } // create newf, err := os.Create(name) if err != nil { return err } defer newf.Close() _, err = newf.WriteString(content) if err != nil { return err } // destroy err = os.Remove(opts.Filename.Val) if err != nil { return err } return nil } func Mv(args []string) { opts := initOpts() help := flags.NewHelpError(CMD, SUMMARY) if err := flags.ParseArgs(help, args, &opts); err != nil { if errors.As(err, &help) { fmt.Println(help) return } log.Fatalf("um %s: %s", CMD, err) } err := mv(opts) if err != nil { log.Fatalf("um %s: %v", CMD, err) } }