mirror of
https://github.com/lima-vm/lima.git
synced 2026-10-28 11:44:35 +08:00
Merge pull request #5640 from deltron-fr/fix/editor-flags
editutil: support editor commands with arguments
This commit is contained in:
4 files changed
+158
-7
No files matched your search
@@ -23,11 +23,15 @@ package editorcmd
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/mattn/go-shellwords"
|
||||
)
|
||||
|
||||
// Detect detects a text editor command.
|
||||
// Returns the editor exec path with arguments if provided.
|
||||
//
|
||||
// Returns an empty string when no editor is found.
|
||||
func Detect() string {
|
||||
func Detect() (editor string, args []string) {
|
||||
candidates := []string{
|
||||
os.Getenv("VISUAL"),
|
||||
os.Getenv("EDITOR"),
|
||||
@@ -40,10 +44,23 @@ func Detect() string {
|
||||
if f == "" {
|
||||
continue
|
||||
}
|
||||
x, err := exec.LookPath(f)
|
||||
if err == nil {
|
||||
return x
|
||||
|
||||
if path, err := exec.LookPath(f); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
parsedArgs, err := shellwords.Parse(f)
|
||||
if err != nil || len(parsedArgs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
path, err := exec.LookPath(parsedArgs[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
return path, parsedArgs[1:]
|
||||
}
|
||||
return ""
|
||||
|
||||
return "", nil
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package editorcmd
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestDetectEditorWithArguments(t *testing.T) {
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", "go --wait")
|
||||
|
||||
expectedPath, err := exec.LookPath("go")
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, expectedPath)
|
||||
assert.DeepEqual(t, args, []string{"--wait"})
|
||||
}
|
||||
|
||||
func TestDetectQuotedEditor(t *testing.T) {
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", `"go"`)
|
||||
|
||||
expectedPath, err := exec.LookPath("go")
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, expectedPath)
|
||||
assert.Equal(t, len(args), 0)
|
||||
}
|
||||
|
||||
func TestDetectQuotedEditorArgument(t *testing.T) {
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", `go -ldflags "-s -w"`)
|
||||
|
||||
expectedPath, err := exec.LookPath("go")
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, expectedPath)
|
||||
assert.DeepEqual(t, args, []string{"-ldflags", "-s -w"})
|
||||
}
|
||||
|
||||
func TestDetectSkipsInvalidEditor(t *testing.T) {
|
||||
t.Setenv("VISUAL", `go -c "unterminated`)
|
||||
t.Setenv("EDITOR", "go --wait")
|
||||
|
||||
expectedPath, err := exec.LookPath("go")
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, expectedPath)
|
||||
assert.DeepEqual(t, args, []string{"--wait"})
|
||||
}
|
||||
|
||||
func TestDetectSkipsEmptyEditor(t *testing.T) {
|
||||
t.Setenv("VISUAL", " ")
|
||||
t.Setenv("EDITOR", "go --wait")
|
||||
|
||||
expectedPath, err := exec.LookPath("go")
|
||||
assert.NilError(t, err)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, expectedPath)
|
||||
assert.DeepEqual(t, args, []string{"--wait"})
|
||||
}
|
||||
|
||||
func TestDetectNoEditor(t *testing.T) {
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", "")
|
||||
t.Setenv("PATH", t.TempDir())
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, "")
|
||||
assert.Equal(t, len(args), 0)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-FileCopyrightText: Copyright The Lima Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build windows
|
||||
|
||||
package editorcmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestDetectWindowsPath(t *testing.T) {
|
||||
editorPath := makeWindowsEditor(t)
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", editorPath)
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, editorPath)
|
||||
assert.Equal(t, len(args), 0)
|
||||
}
|
||||
|
||||
func TestDetectWindowsPathWithArguments(t *testing.T) {
|
||||
editorPath := makeWindowsEditor(t)
|
||||
t.Setenv("VISUAL", "")
|
||||
t.Setenv("EDITOR", fmt.Sprintf(`'%s' --wait`, editorPath))
|
||||
|
||||
path, args := Detect()
|
||||
|
||||
assert.Equal(t, path, editorPath)
|
||||
assert.DeepEqual(t, args, []string{"--wait"})
|
||||
}
|
||||
|
||||
func makeWindowsEditor(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
editorDir := filepath.Join(t.TempDir(), "editor with spaces")
|
||||
assert.NilError(t, os.Mkdir(editorDir, 0o755))
|
||||
editorPath := filepath.Join(editorDir, "editor.exe")
|
||||
assert.NilError(t, os.WriteFile(editorPath, nil, 0o755))
|
||||
return editorPath
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func GenerateEditorWarningHeader() string {
|
||||
//
|
||||
// OpenEditor returns nil when the file was saved as an empty file, optionally with whitespaces.
|
||||
func OpenEditor(ctx context.Context, content []byte, hdr string) ([]byte, error) {
|
||||
editor := editorcmd.Detect()
|
||||
editor, args := editorcmd.Detect()
|
||||
if editor == "" {
|
||||
return nil, errors.New("could not detect a text editor binary, try setting $EDITOR")
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func OpenEditor(ctx context.Context, content []byte, hdr string) ([]byte, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
editorCmd := exec.CommandContext(ctx, editor, tmpYAMLPath)
|
||||
editorCmd := exec.CommandContext(ctx, editor, append(args, tmpYAMLPath)...)
|
||||
editorCmd.Env = os.Environ()
|
||||
editorCmd.Stdin = os.Stdin
|
||||
editorCmd.Stdout = os.Stdout
|
||||
|
||||
Reference in new issue
Block a user