Skip to content

Commit ff79f87

Browse files
authored
Support Default Editor Setting In Windows (#1454)
* feat(editor): implement platform-specific argument parsing for editors - Added `parseEditorArgs` function for Windows and POSIX systems to handle command line arguments for text editors. - Created `editor_windows.go` and `editor_unix.go` files to separate platform-specific implementations. - Introduced tests in `editor_windows_test.go` and `editor_unix_test.go` to ensure correct parsing behavior across different scenarios. - This change enhances compatibility with various text editors by correctly interpreting command line arguments, improving user experience. * docs(README): update default editor instructions for Windows and macOS - Clarified the default text editor settings for Linux/macOS and Windows. - Added examples for setting the `EDITOR` environment variable in PowerShell and Command Prompt on Windows. - Ensured instructions are clear for both terminal and non-terminal editors. * docs(README): update default editor paths for Windows PowerShell - Updated the Notepad++ and Visual Studio Code paths to a more generic format. * docs(README): update default editor examples for Windows and Linux - Included examples for using popular editors like Visual Studio Code and Sublime Text. - Ensured consistency in formatting and improved clarity for users configuring their environment. * refactor(editor_windows): simplify command line argument parsing - Replaced custom argument parsing logic in `parseEditorArgs` with `windows.DecomposeCommandLine` for improved reliability and maintainability. - Removed unnecessary error handling and conversions related to UTF-16 encoding, streamlining the function's implementation.
1 parent 32f15e0 commit ff79f87

6 files changed

Lines changed: 194 additions & 7 deletions

File tree

README.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ Select **y** to proceed with your default tenant, or **N** to choose a different
188188
189189
## Customization
190190
191-
To change the text editor used for editing templates, rules, and actions, set the environment variable `EDITOR` to your
192-
preferred editor. If choosing a non-terminal editor, ensure that the command starts the editor and waits for the files
193-
to be closed before returning.
191+
The default text editor is `vim` on Linux/macOS and `notepad` on Windows. To change that for editing templates, rules, and actions, set the environment variable `EDITOR` to your
192+
preferred editor. If choosing a non-terminal editor, ensure that the command starts the editor and waits for the files to be closed before returning.
194193
195-
Examples:
194+
### Examples:
195+
#### Linux / macOS
196196
197197
```shell
198198
# Uses vscode with the --wait flag.
@@ -208,6 +208,28 @@ export EDITOR="nano"
208208
export EDITOR="vim"
209209
```
210210
211+
#### Windows
212+
213+
```powershell
214+
# PowerShell (current session):
215+
$env:EDITOR = "code --wait"
216+
$env:EDITOR = 'subl --wait'
217+
$env:EDITOR = 'notepad'
218+
$env:EDITOR = '"C:\Path To\executable++.exe" --wait'
219+
# PowerShell (persistent, across sessions):
220+
[System.Environment]::SetEnvironmentVariable("EDITOR", "code --wait", "User")
221+
```
222+
223+
```cmd
224+
REM Command Prompt (current session):
225+
set EDITOR=code --wait
226+
set EDITOR=subl --wait
227+
set EDITOR=notepad
228+
set EDITOR="C:\Path To\executable++.exe" --wait
229+
REM Command Prompt (persistent, across sessions):
230+
setx EDITOR "code --wait"
231+
```
232+
211233
## Anonymized Analytics Disclosure
212234
213235
Anonymized data points are collected during the use of this CLI. This data includes the CLI version, operating system, timestamp, and other technical details that do not personally identify you.

internal/prompt/editor.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"os/exec"
88
"runtime"
99

10-
"github.com/kballard/go-shellquote"
11-
1210
"github.com/auth0/auth0-cli/internal/iostream"
1311
)
1412

@@ -40,7 +38,7 @@ type editorPrompt struct {
4038
// openFile opens filename in the preferred text editor, resolving the
4139
// arguments with editor specific logic.
4240
func (p *editorPrompt) openFile(filename string, infoFn func()) error {
43-
args, err := shellquote.Split(p.cmd)
41+
args, err := parseEditorArgs(p.cmd)
4442
if err != nil {
4543
return err
4644
}

internal/prompt/editor_unix.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package prompt
5+
6+
import (
7+
"github.com/kballard/go-shellquote"
8+
)
9+
10+
// parseEditorArgs parses POSIX shell-style command line arguments
11+
// into a slice of strings suitable for exec.Command.
12+
func parseEditorArgs(cmd string) ([]string, error) {
13+
return shellquote.Split(cmd)
14+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package prompt
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestParseEditorArgs(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
cmd string
17+
expected []string
18+
wantErr bool
19+
}{
20+
{
21+
name: "simple editor",
22+
cmd: "vim",
23+
expected: []string{"vim"},
24+
},
25+
{
26+
name: "editor with flag",
27+
cmd: "code --wait",
28+
expected: []string{"code", "--wait"},
29+
},
30+
{
31+
name: "editor with multiple flags",
32+
cmd: "subl --wait --new-window",
33+
expected: []string{"subl", "--wait", "--new-window"},
34+
},
35+
{
36+
name: "path with spaces in double quotes",
37+
cmd: `"/usr/local/bin/my editor" --wait`,
38+
expected: []string{"/usr/local/bin/my editor", "--wait"},
39+
},
40+
{
41+
name: "path with spaces in single quotes",
42+
cmd: `'/usr/local/bin/my editor' --wait`,
43+
expected: []string{"/usr/local/bin/my editor", "--wait"},
44+
},
45+
{
46+
name: "path without spoaces or quotes",
47+
cmd: `/usr/local/bin/myeditor --wait`,
48+
expected: []string{"/usr/local/bin/myeditor", "--wait"},
49+
},
50+
{
51+
name: "empty command",
52+
cmd: ``,
53+
expected: []string{},
54+
},
55+
{
56+
name: "unterminated quote",
57+
cmd: `"unterminated`,
58+
wantErr: true,
59+
},
60+
}
61+
62+
for _, tt := range tests {
63+
t.Run(tt.name, func(t *testing.T) {
64+
args, err := parseEditorArgs(tt.cmd)
65+
if tt.wantErr {
66+
require.Error(t, err)
67+
return
68+
}
69+
require.NoError(t, err)
70+
assert.Equal(t, tt.expected, args)
71+
})
72+
}
73+
}

internal/prompt/editor_windows.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package prompt
5+
6+
import (
7+
"golang.org/x/sys/windows"
8+
)
9+
10+
func parseEditorArgs(cmd string) ([]string, error) {
11+
return windows.DecomposeCommandLine(cmd)
12+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package prompt
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestParseEditorArgs(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
cmd string
17+
expected []string
18+
wantErr bool
19+
}{
20+
{
21+
name: "simple editor",
22+
cmd: "notepad",
23+
expected: []string{"notepad"},
24+
},
25+
{
26+
name: "editor with flag",
27+
cmd: "code --wait",
28+
expected: []string{"code", "--wait"},
29+
},
30+
{
31+
name: "windows path with backslashes",
32+
cmd: `C:\Windows\notepad.exe`,
33+
expected: []string{`C:\Windows\notepad.exe`},
34+
},
35+
{
36+
name: "quoted path with spaces",
37+
cmd: `"C:\Program Files\Notepad++\notepad++.exe" --wait`,
38+
expected: []string{`C:\Program Files\Notepad++\notepad++.exe`, "--wait"},
39+
},
40+
{
41+
name: "quoted path with spaces and multiple flags",
42+
cmd: `"C:\Program Files\Microsoft VS Code\code.exe" --wait --new-window`,
43+
expected: []string{`C:\Program Files\Microsoft VS Code\code.exe`, "--wait", "--new-window"},
44+
},
45+
{
46+
name: "path without spaces or quotes",
47+
cmd: `C:\tools\vim.exe -u C:\Users\me\.vimrc`,
48+
expected: []string{`C:\tools\vim.exe`, "-u", `C:\Users\me\.vimrc`},
49+
},
50+
{
51+
name: "empty command",
52+
cmd: ``,
53+
expected: []string{},
54+
},
55+
}
56+
57+
for _, tt := range tests {
58+
t.Run(tt.name, func(t *testing.T) {
59+
args, err := parseEditorArgs(tt.cmd)
60+
if tt.wantErr {
61+
require.Error(t, err)
62+
return
63+
}
64+
require.NoError(t, err)
65+
assert.Equal(t, tt.expected, args)
66+
})
67+
}
68+
}

0 commit comments

Comments
 (0)