mirror of
https://github.com/cheat/cheat.git
synced 2026-05-27 19:48:44 +02:00
9b92261604
Replace docopt-go with spf13/cobra, giving cheat a built-in `--completion` flag that dynamically generates shell completions for bash, zsh, fish, and powershell. This replaces the manually-maintained static completion scripts and resolves the root cause of multiple completion issues (#768, #705, #633, #632, #476). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
2.9 KiB
Go
108 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/cheat/cheat/internal/cheatpath"
|
|
"github.com/cheat/cheat/internal/config"
|
|
"github.com/cheat/cheat/internal/sheet"
|
|
"github.com/cheat/cheat/internal/sheets"
|
|
)
|
|
|
|
// cmdEdit opens a cheatsheet for editing (or creates it if it doesn't exist).
|
|
func cmdEdit(cmd *cobra.Command, _ []string, conf config.Config) {
|
|
|
|
cheatsheet, _ := cmd.Flags().GetString("edit")
|
|
|
|
// validate the cheatsheet name
|
|
if err := sheet.Validate(cheatsheet); err != nil {
|
|
fmt.Fprintf(os.Stderr, "invalid cheatsheet name: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// load the cheatsheets
|
|
cheatsheets, err := sheets.Load(conf.Cheatpaths)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if cmd.Flags().Changed("tag") {
|
|
tagVal, _ := cmd.Flags().GetString("tag")
|
|
cheatsheets = sheets.Filter(
|
|
cheatsheets,
|
|
strings.Split(tagVal, ","),
|
|
)
|
|
}
|
|
|
|
// consolidate the cheatsheets found on all paths into a single map of
|
|
// `title` => `sheet` (ie, allow more local cheatsheets to override less
|
|
// local cheatsheets)
|
|
consolidated := sheets.Consolidate(cheatsheets)
|
|
|
|
// the file path of the sheet to edit
|
|
var editpath string
|
|
|
|
// determine if the sheet exists
|
|
sheet, ok := consolidated[cheatsheet]
|
|
|
|
// if the sheet exists and is not read-only, edit it in place
|
|
if ok && !sheet.ReadOnly {
|
|
editpath = sheet.Path
|
|
} else {
|
|
// for read-only or non-existent sheets, resolve a writeable path
|
|
writepath, err := cheatpath.Writeable(conf.Cheatpaths)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to get writeable path: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// use the existing title for read-only copies, the requested name otherwise
|
|
title := cheatsheet
|
|
if ok {
|
|
title = sheet.Title
|
|
}
|
|
editpath = filepath.Join(writepath.Path, title)
|
|
|
|
if ok {
|
|
// copy the read-only sheet to the writeable path
|
|
// (Copy handles MkdirAll internally)
|
|
if err := sheet.Copy(editpath); err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to copy cheatsheet: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
} else {
|
|
// create any necessary subdirectories for the new sheet
|
|
dirs := filepath.Dir(editpath)
|
|
if dirs != "." {
|
|
if err := os.MkdirAll(dirs, 0755); err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to create directory: %s, %v\n", dirs, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// split `conf.Editor` into parts to separate the editor's executable from
|
|
// any arguments it may have been passed. If this is not done, the nearby
|
|
// call to `exec.Command` will fail.
|
|
parts := strings.Fields(conf.Editor)
|
|
editor := parts[0]
|
|
editorArgs := append(parts[1:], editpath)
|
|
|
|
// edit the cheatsheet
|
|
editorCmd := exec.Command(editor, editorArgs...)
|
|
editorCmd.Stdout = os.Stdout
|
|
editorCmd.Stdin = os.Stdin
|
|
editorCmd.Stderr = os.Stderr
|
|
if err := editorCmd.Run(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to edit cheatsheet: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|