Skip to content

Commit 4d1cf6f

Browse files
committed
feat: added editor to config file
1 parent 5dd4da3 commit 4d1cf6f

File tree

4 files changed

+116
-56
lines changed

4 files changed

+116
-56
lines changed

config.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ import (
1717
// At the moment, it is quite limited, only supporting the home folder and the
1818
// file name of the metadata.
1919
type Config struct {
20-
Home string `env:"NAP_HOME" yaml:"home"`
21-
File string `env:"NAP_FILE" yaml:"file"`
22-
20+
Home string `env:"NAP_HOME" yaml:"home"`
21+
File string `env:"NAP_FILE" yaml:"file"`
22+
Editor string `env:"NAP_EDITOR" yaml:"editor"`
2323
DefaultLanguage string `env:"NAP_DEFAULT_LANGUAGE" yaml:"default_language"`
2424

25-
Theme string `env:"NAP_THEME" yaml:"theme"`
26-
25+
Theme string `env:"NAP_THEME" yaml:"theme"`
2726
BackgroundColor string `env:"NAP_BACKGROUND" yaml:"background"`
2827
ForegroundColor string `env:"NAP_FOREGROUND" yaml:"foreground"`
2928
BlackColor string `env:"NAP_BLACK" yaml:"black"`
@@ -44,6 +43,7 @@ func newConfig() Config {
4443
Home: defaultHome(),
4544
File: "snippets.json",
4645
DefaultLanguage: defaultLanguage,
46+
Editor: "", // defined at config build
4747
Theme: "dracula",
4848
BackgroundColor: "235",
4949
ForegroundColor: "15",
@@ -69,11 +69,10 @@ func defaultConfig() string {
6969
if c := os.Getenv("NAP_CONFIG"); c != "" {
7070
return c
7171
}
72-
cfgPath, err := xdg.ConfigFile("nap/config.yaml")
73-
if err != nil {
74-
return "config.yaml"
72+
if cfgPath, err := xdg.ConfigFile("nap/config.yaml"); err == nil {
73+
return cfgPath
7574
}
76-
return cfgPath
75+
return "config.yaml"
7776
}
7877

7978
// readConfig returns a configuration read from the environment.
@@ -89,7 +88,6 @@ func readConfig() Config {
8988
return newConfig()
9089
}
9190
}
92-
9391
if err := env.Parse(&config); err != nil {
9492
return newConfig()
9593
}
@@ -100,6 +98,9 @@ func readConfig() Config {
10098
config.Home = filepath.Join(home, config.Home[1:])
10199
}
102100
}
101+
if config.Editor == "" {
102+
config.Editor = getEditor()
103+
}
103104

104105
return config
105106
}

editor.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@ import (
88

99
const defaultEditor = "nano"
1010

11-
// Cmd returns a *exec.Cmd editing the given path with $EDITOR or nano if no
12-
// $EDITOR is set.
13-
func editorCmd(path string) *exec.Cmd {
14-
editor, args := getEditor()
15-
return exec.Command(editor, append(args, path)...)
11+
func getEditor() string {
12+
if v := os.Getenv("VISUAL"); v != "" {
13+
return v
14+
}
15+
if e := os.Getenv("EDITOR"); e != "" {
16+
return e
17+
}
18+
return defaultEditor
1619
}
1720

18-
func getEditor() (string, []string) {
19-
editor := strings.Fields(os.Getenv("EDITOR"))
20-
if len(editor) > 0 {
21-
return editor[0], editor[1:]
21+
// editorCmd creates a command to edit the given path using the specified editor string.
22+
func editorCmd(editor, path string) *exec.Cmd {
23+
if c := strings.Fields(editor); len(c) > 0 {
24+
return exec.Command(c[0], append(c[1:], path)...)
2225
}
23-
return defaultEditor, nil
26+
return nil
2427
}

editor_test.go

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,120 @@
11
package main
22

33
import (
4-
"fmt"
54
"os"
5+
"path/filepath"
66
"testing"
77
)
88

99
func TestGetEditor(t *testing.T) {
1010
tt := []struct {
11-
Name string
12-
EditorEnv string
13-
Cmd string
14-
Args []string
11+
name string
12+
visual string
13+
editor string
14+
expected string
1515
}{
1616
{
17-
Name: "default",
18-
Cmd: "nano",
17+
name: "default",
18+
expected: "nano",
1919
},
2020
{
21-
Name: "vim",
22-
EditorEnv: "vim",
23-
Cmd: "vim",
21+
name: "$EDITOR only",
22+
editor: "vim",
23+
expected: "vim",
2424
},
2525
{
26-
Name: "vim with flag",
27-
EditorEnv: "vim --foo",
28-
Cmd: "vim",
29-
Args: []string{"--foo"},
26+
name: "$VISUAL only",
27+
visual: "code -w",
28+
expected: "code -w",
3029
},
3130
{
32-
Name: "code",
33-
EditorEnv: "code -w",
34-
Cmd: "code",
35-
Args: []string{"-w"},
31+
name: "both set - $VISIAL wins",
32+
visual: "code -w",
33+
editor: "vim",
34+
expected: "code -w",
3635
},
3736
}
3837

3938
for _, tc := range tt {
40-
t.Run(tc.Name, func(t *testing.T) {
41-
var err error
42-
switch tc.EditorEnv {
43-
case "":
44-
err = os.Unsetenv("EDITOR")
45-
default:
46-
err = os.Setenv("EDITOR", tc.EditorEnv)
39+
t.Run(tc.name, func(t *testing.T) {
40+
if tc.visual != "" {
41+
os.Setenv("VISUAL", tc.visual)
42+
} else {
43+
os.Unsetenv("VISUAL")
4744
}
48-
if err != nil {
49-
t.Logf("could not (un)set env: %v", err)
50-
t.FailNow()
45+
if tc.editor != "" {
46+
os.Setenv("EDITOR", tc.editor)
47+
} else {
48+
os.Unsetenv("EDITOR")
5149
}
5250

53-
cmd, args := getEditor()
51+
got := getEditor()
52+
if got != tc.expected {
53+
t.Errorf("getEditor() = %v, want %v", got, tc.expected)
54+
}
55+
})
56+
}
57+
}
58+
59+
func TestEditorCmd(t *testing.T) {
60+
tt := []struct {
61+
name string
62+
editor string
63+
path string
64+
wantCmd string
65+
wantArgs []string
66+
}{
67+
{
68+
name: "simple editor",
69+
editor: "nano",
70+
path: "test.txt",
71+
wantCmd: "nano",
72+
wantArgs: []string{"test.txt"},
73+
},
74+
{
75+
name: "editor with flags",
76+
editor: "code --wait",
77+
path: "test.txt",
78+
wantCmd: "code",
79+
wantArgs: []string{"--wait", "test.txt"},
80+
},
81+
{
82+
name: "empty editor",
83+
editor: "",
84+
path: "test.txt",
85+
wantCmd: "",
86+
wantArgs: nil,
87+
},
88+
}
89+
90+
for _, tc := range tt {
91+
t.Run(tc.name, func(t *testing.T) {
92+
cmd := editorCmd(tc.editor, tc.path)
93+
if tc.editor == "" {
94+
if cmd != nil {
95+
t.Errorf("editorCmd() = %v, want nil", cmd)
96+
}
97+
return
98+
}
99+
100+
if filepath.Base(cmd.Path) != tc.wantCmd {
101+
t.Errorf("cmd.Path = %v, want %v", cmd.Path, tc.wantCmd)
102+
}
103+
104+
if len(cmd.Args) < 2 {
105+
t.Errorf("cmd.Args too short = %v", cmd.Args)
106+
return
107+
}
54108

55-
if cmd != tc.Cmd {
56-
t.Logf("cmd is incorrect: want %q but got %q", tc.Cmd, cmd)
57-
t.FailNow()
109+
gotArgs := cmd.Args[1:]
110+
if len(gotArgs) != len(tc.wantArgs) {
111+
t.Errorf("cmd.Args = %v, want %v", gotArgs, tc.wantArgs)
58112
}
59113

60-
if argStr, tcArgStr := fmt.Sprint(args), fmt.Sprint(tc.Args); argStr != tcArgStr {
61-
t.Logf("args are incorrect: want %q but got %q", tcArgStr, argStr)
62-
t.FailNow()
114+
for i := range gotArgs {
115+
if gotArgs[i] != tc.wantArgs[i] {
116+
t.Errorf("cmd.Args[%d] = %v, want %v", i, gotArgs[i], tc.wantArgs[i])
117+
}
63118
}
64119
})
65120
}

model.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ func (m *Model) previousPane() {
385385

386386
// editSnippet opens the editor with the selected snippet file path.
387387
func (m *Model) editSnippet() tea.Cmd {
388-
return tea.ExecProcess(editorCmd(m.selectedSnippetFilePath()), func(err error) tea.Msg {
388+
cmd := editorCmd(m.config.Editor, m.selectedSnippetFilePath())
389+
return tea.ExecProcess(cmd, func(err error) tea.Msg {
389390
return updateContentMsg(m.selectedSnippet())
390391
})
391392
}

0 commit comments

Comments
 (0)