test: TestEditorParsing
(cherry picked from commit e44b53a7c9b73dd2b7df514f9633b1c992504d4c)
Marcin Rataj committed
Jul 8, 2025 at 18:28 UTC
d3a4558f6921bdfcb4f4be2bcab64961dc09d6d4
2 files changed
+119
-1
core/commands/config.go
+6
-1
@@ -506,13 +506,18 @@ func setConfig(r repo.Repo, key string, value interface{}) (*ConfigField, error)
506
return getConfig(r, key)
507
}
508
509
+// parseEditorCommand parses the EDITOR environment variable into command and arguments
510
+func parseEditorCommand(editor string) ([]string, error) {
511
+ return shlex.Split(editor, true)
512
+}
513
+
514
func editConfig(filename string) error {
515
editor := os.Getenv("EDITOR")
516
if editor == "" {
517
return errors.New("ENV variable $EDITOR not set")
518
}
519
515
- editorAndArgs, err := shlex.Split(editor, true)
520
+ editorAndArgs, err := parseEditorCommand(editor)
521
if err != nil {
522
return fmt.Errorf("cannot parse $EDITOR value: %s", err)
523
}
core/commands/config_test.go
+113
@@ -14,3 +14,116 @@ func TestScrubMapInternalDelete(t *testing.T) {
14
t.Errorf("expecting an empty map, got a non-empty map")
15
}
16
}
17
+
18
+func TestEditorParsing(t *testing.T) {
19
+ testCases := []struct {
20
+ name string
21
+ input string
22
+ expected []string
23
+ hasError bool
24
+ }{
25
+ {
26
+ name: "simple editor",
27
+ input: "vim",
28
+ expected: []string{"vim"},
29
+ hasError: false,
30
+ },
31
+ {
32
+ name: "editor with single flag",
33
+ input: "emacs -nw",
34
+ expected: []string{"emacs", "-nw"},
35
+ hasError: false,
36
+ },
37
+ {
38
+ name: "VS Code with wait flag (issue #9375)",
39
+ input: "code --wait",
40
+ expected: []string{"code", "--wait"},
41
+ hasError: false,
42
+ },
43
+ {
44
+ name: "VS Code with full path and wait flag (issue #9375)",
45
+ input: "/opt/homebrew/bin/code --wait",
46
+ expected: []string{"/opt/homebrew/bin/code", "--wait"},
47
+ hasError: false,
48
+ },
49
+ {
50
+ name: "editor with quoted path containing spaces",
51
+ input: "\"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code\" --wait",
52
+ expected: []string{"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "--wait"},
53
+ hasError: false,
54
+ },
55
+ {
56
+ name: "sublime text with wait flag",
57
+ input: "subl -w",
58
+ expected: []string{"subl", "-w"},
59
+ hasError: false,
60
+ },
61
+ {
62
+ name: "nano editor",
63
+ input: "nano",
64
+ expected: []string{"nano"},
65
+ hasError: false,
66
+ },
67
+ {
68
+ name: "gedit editor",
69
+ input: "gedit",
70
+ expected: []string{"gedit"},
71
+ hasError: false,
72
+ },
73
+ {
74
+ name: "editor with multiple flags",
75
+ input: "vim -c 'set number' -c 'set hlsearch'",
76
+ expected: []string{"vim", "-c", "set number", "-c", "set hlsearch"},
77
+ hasError: false,
78
+ },
79
+ {
80
+ name: "trailing backslash (POSIX edge case)",
81
+ input: "editor\\",
82
+ expected: nil,
83
+ hasError: true,
84
+ },
85
+ {
86
+ name: "double quoted editor name with spaces",
87
+ input: "\"code with spaces\" --wait",
88
+ expected: []string{"code with spaces", "--wait"},
89
+ hasError: false,
90
+ },
91
+ {
92
+ name: "single quoted editor with flags",
93
+ input: "'my editor' -flag",
94
+ expected: []string{"my editor", "-flag"},
95
+ hasError: false,
96
+ },
97
+ }
98
+
99
+ for _, tc := range testCases {
100
+ t.Run(tc.name, func(t *testing.T) {
101
+ result, err := parseEditorCommand(tc.input)
102
+
103
+ if tc.hasError {
104
+ if err == nil {
105
+ t.Errorf("Expected error for input '%s', but got none", tc.input)
106
+ }
107
+ return
108
+ }
109
+
110
+ if err != nil {
111
+ t.Errorf("Unexpected error for input '%s': %v", tc.input, err)
112
+ return
113
+ }
114
+
115
+ if len(result) != len(tc.expected) {
116
+ t.Errorf("Expected %d args, got %d for input '%s'", len(tc.expected), len(result), tc.input)
117
+ t.Errorf("Expected: %v", tc.expected)
118
+ t.Errorf("Got: %v", result)
119
+ return
120
+ }
121
+
122
+ for i, expected := range tc.expected {
123
+ if result[i] != expected {
124
+ t.Errorf("Expected arg %d to be '%s', got '%s' for input '%s'", i, expected, result[i], tc.input)
125
+ }
126
+ }
127
+ })
128
+ }
129
+}