Skip to content

Commit

Permalink
Solidify editor mechanics
Browse files Browse the repository at this point in the history
I've looked into what github does, so they use a mix of this approach, and
the survey approach.

To keep it simple, we're only gonna go with the manual approach they do until
we feel the full blown prompt approach is necessary.

Closes #189
  • Loading branch information
cyx committed Apr 2, 2021
1 parent e3785f7 commit ee6ff7a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 33 deletions.
24 changes: 15 additions & 9 deletions internal/cli/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ func rulesCmd(cli *cli) *cobra.Command {

func listRulesCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Use: "list",
Aliases: []string{"ls"},
Short: "List your rules",
Long: `List the rules in your current tenant.`,
Short: "List your rules",
Long: `List the rules in your current tenant.`,
Example: `auth0 rules list
auth0 rules ls`,
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -106,9 +106,9 @@ func createRuleCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new rule",
Long: `Create a new rule:`,
Example: `auth0 rules create
auth0 rules create --name "My Rule"
Long: `Create a new rule:`,
Example: `auth0 rules create
auth0 rules create --name "My Rule"
auth0 rules create -n "My Rule" --template "Empty rule"
auth0 rules create -n "My Rule" -t "Empty rule" --enabled=false`,
PreRun: func(cmd *cobra.Command, args []string) {
Expand All @@ -129,6 +129,9 @@ auth0 rules create -n "My Rule" -t "Empty rule" --enabled=false`,
script, err := prompt.CaptureInputViaEditor(
ruleTemplateOptions.getValue(inputs.Template),
inputs.Name+".*.js",
func() {
cli.renderer.Infof("%s once you close the editor, the rule will be saved. To cancel, CTRL+C.", ansi.Faint("Hint:"))
},
)
if err != nil {
return fmt.Errorf("Failed to capture input from the editor: %w", err)
Expand Down Expand Up @@ -169,7 +172,7 @@ func showRuleCmd(cli *cli) *cobra.Command {
Use: "show",
Args: cobra.MaximumNArgs(1),
Short: "Show a rule",
Long: `Show a rule:`,
Long: `Show a rule:`,
Example: `auth0 rules show
auth0 rules show <id>`,
PreRun: func(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -213,7 +216,7 @@ func deleteRuleCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
Short: "Delete a rule",
Long: `Delete a rule`,
Long: `Delete a rule`,
Example: `auth0 rules delete
auth0 rules delete <rule-id>`,
PreRun: func(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -254,7 +257,7 @@ func updateRuleCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: "Update a rule",
Long: `Update a rule`,
Long: `Update a rule`,
Example: `auth0 rules update <rule-id>
auth0 rules update <rule-id> --name "My Updated Rule"
auth0 rules update <rule-id> -n "My Updated Rule" --enabled=false`,
Expand Down Expand Up @@ -291,6 +294,9 @@ auth0 rules update <rule-id> -n "My Updated Rule" --enabled=false`,
script, err := prompt.CaptureInputViaEditor(
rule.GetScript(),
rule.GetName()+".*.js",
func() {
cli.renderer.Infof("%s once you close the editor, the rule will be saved. To cancel, CTRL+C.", ansi.Faint("Hint:"))
},
)
if err != nil {
return fmt.Errorf("Failed to capture input from the editor: %w", err)
Expand Down
58 changes: 34 additions & 24 deletions internal/prompt/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"os/exec"
"runtime"

"github.com/kballard/go-shellquote"
)
Expand All @@ -14,48 +15,58 @@ const (
)

var (
bom = []byte{0xef, 0xbb, 0xbf}
bom = []byte{0xef, 0xbb, 0xbf}
cliEditors = []string{"vi", "vim", "nano"}
)

var defaultEditorPrompt = &editorPrompt{defaultEditor: defaultEditor}
var defaultEditorPrompt = &editorPrompt{editorCmd: getDefaultEditor()}

// CaptureInputViaEditor is the high level function to use in this package in
// order to capture input from an editor.
//
// The arguments have been tailored for our use of strings mostly in the rest
// of the CLI even though internally we're using []byte.
func CaptureInputViaEditor(contents, pattern string) (result string, err error) {
v, err := defaultEditorPrompt.captureInput([]byte(contents), pattern)
func CaptureInputViaEditor(contents, pattern string, infoFn func()) (result string, err error) {
v, err := defaultEditorPrompt.captureInput([]byte(contents), pattern, infoFn)
return string(v), err
}

type editorPrompt struct {
defaultEditor string
editorCmd string
}

// GetPreferredEditorFromEnvironment returns the user's editor as defined by the
// `$EDITOR` environment variable, or the `defaultEditor` if it is not set.
func (p *editorPrompt) getPreferredEditor() string {
editor := os.Getenv("EDITOR")

if editor == "" {
return p.defaultEditor
// getDefaultEditor is taken from https://github.com/cli/cli/blob/trunk/pkg/surveyext/editor_manual.go
// and tries to infer the editor from different heuristics.
func getDefaultEditor() string {
if runtime.GOOS == "windows" {
return "notepad"
} else if g := os.Getenv("GIT_EDITOR"); g != "" {
return g
} else if v := os.Getenv("VISUAL"); v != "" {
return v
} else if e := os.Getenv("EDITOR"); e != "" {
return e
}

return editor
return defaultEditor
}

// openFile opens filename in the preferred text editor, resolving the
// arguments with editor specific logic.
func (p *editorPrompt) openFile(filename string) error {
editorCommand := p.getPreferredEditor()

args, err := shellquote.Split(editorCommand)
func (p *editorPrompt) openFile(filename string, infoFn func()) error {
args, err := shellquote.Split(p.editorCmd)
if err != nil {
return err
}
args = append(args, filename)

isCLIEditor := false
for _, e := range cliEditors {
if e == args[0] {
isCLIEditor = true
}
}

editorExe, err := exec.LookPath(args[0])
if err != nil {
return err
Expand All @@ -66,6 +77,10 @@ func (p *editorPrompt) openFile(filename string) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if !isCLIEditor && infoFn != nil {
infoFn()
}

return cmd.Run()
}

Expand All @@ -75,7 +90,7 @@ func (p *editorPrompt) openFile(filename string) error {
//
// If given default contents, it will write that to the file before popping
// open the editor.
func (p *editorPrompt) captureInput(contents []byte, pattern string) ([]byte, error) {
func (p *editorPrompt) captureInput(contents []byte, pattern string, infoFn func()) ([]byte, error) {
file, err := os.CreateTemp(os.TempDir(), pattern)
if err != nil {
return []byte{}, err
Expand All @@ -102,16 +117,11 @@ func (p *editorPrompt) captureInput(contents []byte, pattern string) ([]byte, er
}
}

// close the fd to allow the editor to save file
if err := file.Close(); err != nil {
return nil, err
}

if err = file.Close(); err != nil {
return nil, err
}

if err = p.openFile(filename); err != nil {
if err = p.openFile(filename, infoFn); err != nil {
return nil, err
}

Expand Down

0 comments on commit ee6ff7a

Please sign in to comment.