Skip to content

Commit c0fc720

Browse files
committed
fixed review comments
1 parent c9b7b44 commit c0fc720

4 files changed

Lines changed: 71 additions & 32 deletions

File tree

cmd/cli/readline/editor.go

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,76 @@
11
package readline
22

33
import (
4+
"fmt"
45
"os"
56
"os/exec"
67
"runtime"
78
"strings"
89
)
910

10-
func runEditor(content string, defaultEditor string) (string, error) {
11+
const (
12+
defaultEditor = "vi"
13+
defaultShell = "/bin/bash"
14+
windowsEditor = "notepad"
15+
windowsShell = "cmd"
16+
)
17+
18+
func platformize(linux, windows string) string {
19+
if runtime.GOOS == "windows" {
20+
return windows
21+
}
22+
return linux
23+
}
24+
25+
func defaultEnvShell() []string {
26+
shell := os.Getenv("SHELL")
27+
if len(shell) == 0 {
28+
shell = platformize(defaultShell, windowsShell)
29+
}
30+
flag := "-c"
31+
if shell == windowsShell {
32+
flag = "/C"
33+
}
34+
return []string{shell, flag}
35+
}
36+
37+
func resolveEditor() ([]string, bool) {
38+
editor := strings.TrimSpace(os.Getenv("EDITOR"))
39+
if len(editor) == 0 {
40+
editor = platformize(defaultEditor, windowsEditor)
41+
}
42+
43+
if !strings.Contains(editor, " ") {
44+
return []string{editor}, false
45+
}
46+
47+
if !strings.ContainsAny(editor, "\"'\\") {
48+
return strings.Split(editor, " "), false
49+
}
50+
51+
shell := defaultEnvShell()
52+
return append(shell, editor), true
53+
}
54+
55+
func buildEditorCmd(filePath string) *exec.Cmd {
56+
args, shell := resolveEditor()
57+
58+
if shell {
59+
// The editor string is the last element — append the file path to it
60+
// so the shell interprets the full command.
61+
args[len(args)-1] = fmt.Sprintf("%s %s", args[len(args)-1], filePath)
62+
} else {
63+
args = append(args, filePath)
64+
}
65+
66+
cmd := exec.Command(args[0], args[1:]...)
67+
cmd.Stdin = os.Stdin
68+
cmd.Stdout = os.Stdout
69+
cmd.Stderr = os.Stderr
70+
return cmd
71+
}
72+
73+
func runEditor(content string) (string, error) {
1174
tmpFile, err := os.CreateTemp("", "docker-model-prompt-*.txt")
1275
if err != nil {
1376
return content, err
@@ -20,7 +83,7 @@ func runEditor(content string, defaultEditor string) (string, error) {
2083
}
2184
tmpFile.Close()
2285

23-
cmd := buildEditorCmd(defaultEditor, tmpFile.Name())
86+
cmd := buildEditorCmd(tmpFile.Name())
2487
if err := cmd.Run(); err != nil {
2588
return content, err
2689
}
@@ -30,25 +93,5 @@ func runEditor(content string, defaultEditor string) (string, error) {
3093
return content, err
3194
}
3295

33-
result := strings.TrimRight(string(edited), "\r\n")
34-
35-
return result, nil
36-
}
37-
38-
func buildEditorCmd(defaultEditor string, filePath string) *exec.Cmd {
39-
editor := strings.TrimSpace(os.Getenv("EDITOR"))
40-
if editor == "" {
41-
editor = defaultEditor
42-
}
43-
44-
var cmd *exec.Cmd
45-
if runtime.GOOS == "windows" {
46-
cmd = exec.Command("cmd", "/C", editor+" \""+filePath+"\"")
47-
} else {
48-
cmd = exec.Command("sh", "-c", editor+" \"$1\"", "--", filePath)
49-
}
50-
cmd.Stdin = os.Stdin
51-
cmd.Stdout = os.Stdout
52-
cmd.Stderr = os.Stderr
53-
return cmd
96+
return strings.TrimRight(string(edited), "\r\n"), nil
5497
}

cmd/cli/readline/editor_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestRunEditor(t *testing.T) {
5555
t.Run(tt.name, func(t *testing.T) {
5656
createMockEditor(t, tt.mockEditorScript)
5757

58-
result, err := runEditor(tt.input, "vi")
58+
result, err := runEditor(tt.input)
5959
if err != nil {
6060
t.Fatalf("runEditor failed: %v", err)
6161
}
@@ -71,7 +71,7 @@ func TestRunEditorReturnsOriginalContentOnFailure(t *testing.T) {
7171
t.Setenv("EDITOR", "non_exists_editor")
7272

7373
content := "docker model prompt hello"
74-
result, err := runEditor(content, "vi")
74+
result, err := runEditor(content)
7575
if err == nil {
7676
t.Fatal("expected error from nonexistent editor")
7777
}
@@ -85,7 +85,7 @@ func TestRunEditorWithEditorArgs(t *testing.T) {
8585
editorScript := createMockEditor(t, `printf "edited with args" > "$2"`)
8686
t.Setenv("EDITOR", editorScript+" --wait")
8787

88-
result, err := runEditor("original", "vi")
88+
result, err := runEditor("original")
8989
if err != nil {
9090
t.Fatalf("runEditor failed: %v", err)
9191
}

cmd/cli/readline/readline_unix.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@ func openInEditor(fd uintptr, termios any, content string) (string, error) {
2525
return content, err
2626
}
2727

28-
edited, err := runEditor(content, "vi")
28+
edited, err := runEditor(content)
2929

30-
// Always restore raw mode using the original termios, whether the editor
31-
// succeeded or failed, so the terminal returns to its previous configuration.
3230
if _, restoreErr := SetRawMode(fd); restoreErr != nil {
3331
return content, restoreErr
3432
}

cmd/cli/readline/readline_windows.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ func openInEditor(fd uintptr, termios any, content string) (string, error) {
1212
return content, err
1313
}
1414

15-
edited, err := runEditor(content, "notepad")
15+
edited, err := runEditor(content)
1616

17-
// Always restore raw mode using the original state, whether the editor
18-
// succeeded or failed, so the terminal returns to its previous configuration.
1917
if _, restoreErr := SetRawMode(fd); restoreErr != nil {
2018
return content, restoreErr
2119
}

0 commit comments

Comments
 (0)