Skip to content

Commit

Permalink
feat: added editor to config file
Browse files Browse the repository at this point in the history
Updated env lib to v11
  • Loading branch information
korikhin committed Dec 29, 2024
1 parent 5dd4da3 commit a477327
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 56 deletions.
21 changes: 11 additions & 10 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ import (
// At the moment, it is quite limited, only supporting the home folder and the
// file name of the metadata.
type Config struct {
Home string `env:"NAP_HOME" yaml:"home"`
File string `env:"NAP_FILE" yaml:"file"`

Home string `env:"NAP_HOME" yaml:"home"`
File string `env:"NAP_FILE" yaml:"file"`
Editor string `env:"NAP_EDITOR" yaml:"editor"`
DefaultLanguage string `env:"NAP_DEFAULT_LANGUAGE" yaml:"default_language"`

Theme string `env:"NAP_THEME" yaml:"theme"`

Theme string `env:"NAP_THEME" yaml:"theme"`
BackgroundColor string `env:"NAP_BACKGROUND" yaml:"background"`
ForegroundColor string `env:"NAP_FOREGROUND" yaml:"foreground"`
BlackColor string `env:"NAP_BLACK" yaml:"black"`
Expand All @@ -44,6 +43,7 @@ func newConfig() Config {
Home: defaultHome(),
File: "snippets.json",
DefaultLanguage: defaultLanguage,
Editor: "", // defined at config build
Theme: "dracula",
BackgroundColor: "235",
ForegroundColor: "15",
Expand All @@ -69,11 +69,10 @@ func defaultConfig() string {
if c := os.Getenv("NAP_CONFIG"); c != "" {
return c
}
cfgPath, err := xdg.ConfigFile("nap/config.yaml")
if err != nil {
return "config.yaml"
if cfgPath, err := xdg.ConfigFile("nap/config.yaml"); err == nil {
return cfgPath
}
return cfgPath
return "config.yaml"
}

// readConfig returns a configuration read from the environment.
Expand All @@ -89,7 +88,6 @@ func readConfig() Config {
return newConfig()
}
}

if err := env.Parse(&config); err != nil {
return newConfig()
}
Expand All @@ -100,6 +98,9 @@ func readConfig() Config {
config.Home = filepath.Join(home, config.Home[1:])
}
}
if config.Editor == "" {
config.Editor = getEditor()
}

return config
}
Expand Down
23 changes: 13 additions & 10 deletions editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ import (

const defaultEditor = "nano"

// Cmd returns a *exec.Cmd editing the given path with $EDITOR or nano if no
// $EDITOR is set.
func editorCmd(path string) *exec.Cmd {
editor, args := getEditor()
return exec.Command(editor, append(args, path)...)
func getEditor() string {
if v := os.Getenv("VISUAL"); v != "" {
return v
}
if e := os.Getenv("EDITOR"); e != "" {
return e
}
return defaultEditor
}

func getEditor() (string, []string) {
editor := strings.Fields(os.Getenv("EDITOR"))
if len(editor) > 0 {
return editor[0], editor[1:]
// editorCmd creates a command to edit the given path using the specified editor string.
func editorCmd(editor, path string) *exec.Cmd {
if c := strings.Fields(editor); len(c) > 0 {
return exec.Command(c[0], append(c[1:], path)...)
}
return defaultEditor, nil
return nil
}
125 changes: 90 additions & 35 deletions editor_test.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,120 @@
package main

import (
"fmt"
"os"
"path/filepath"
"testing"
)

func TestGetEditor(t *testing.T) {
tt := []struct {
Name string
EditorEnv string
Cmd string
Args []string
name string
visual string
editor string
expected string
}{
{
Name: "default",
Cmd: "nano",
name: "default",
expected: "nano",
},
{
Name: "vim",
EditorEnv: "vim",
Cmd: "vim",
name: "$EDITOR only",
editor: "vim",
expected: "vim",
},
{
Name: "vim with flag",
EditorEnv: "vim --foo",
Cmd: "vim",
Args: []string{"--foo"},
name: "$VISUAL only",
visual: "code -w",
expected: "code -w",
},
{
Name: "code",
EditorEnv: "code -w",
Cmd: "code",
Args: []string{"-w"},
name: "both set - $VISIAL wins",
visual: "code -w",
editor: "vim",
expected: "code -w",
},
}

for _, tc := range tt {
t.Run(tc.Name, func(t *testing.T) {
var err error
switch tc.EditorEnv {
case "":
err = os.Unsetenv("EDITOR")
default:
err = os.Setenv("EDITOR", tc.EditorEnv)
t.Run(tc.name, func(t *testing.T) {
if tc.visual != "" {
os.Setenv("VISUAL", tc.visual)
} else {
os.Unsetenv("VISUAL")
}
if err != nil {
t.Logf("could not (un)set env: %v", err)
t.FailNow()
if tc.editor != "" {
os.Setenv("EDITOR", tc.editor)
} else {
os.Unsetenv("EDITOR")
}

cmd, args := getEditor()
got := getEditor()
if got != tc.expected {
t.Errorf("getEditor() = %v, want %v", got, tc.expected)
}
})
}
}

func TestEditorCmd(t *testing.T) {
tt := []struct {
name string
editor string
path string
wantCmd string
wantArgs []string
}{
{
name: "simple editor",
editor: "nano",
path: "test.txt",
wantCmd: "nano",
wantArgs: []string{"test.txt"},
},
{
name: "editor with flags",
editor: "code --wait",
path: "test.txt",
wantCmd: "code",
wantArgs: []string{"--wait", "test.txt"},
},
{
name: "empty editor",
editor: "",
path: "test.txt",
wantCmd: "",
wantArgs: nil,
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
cmd := editorCmd(tc.editor, tc.path)
if tc.editor == "" {
if cmd != nil {
t.Errorf("editorCmd() = %v, want nil", cmd)
}
return
}

if filepath.Base(cmd.Path) != tc.wantCmd {
t.Errorf("cmd.Path = %v, want %v", cmd.Path, tc.wantCmd)
}

if len(cmd.Args) < 2 {
t.Errorf("cmd.Args too short = %v", cmd.Args)
return
}

if cmd != tc.Cmd {
t.Logf("cmd is incorrect: want %q but got %q", tc.Cmd, cmd)
t.FailNow()
gotArgs := cmd.Args[1:]
if len(gotArgs) != len(tc.wantArgs) {
t.Errorf("cmd.Args = %v, want %v", gotArgs, tc.wantArgs)
}

if argStr, tcArgStr := fmt.Sprint(args), fmt.Sprint(tc.Args); argStr != tcArgStr {
t.Logf("args are incorrect: want %q but got %q", tcArgStr, argStr)
t.FailNow()
for i := range gotArgs {
if gotArgs[i] != tc.wantArgs[i] {
t.Errorf("cmd.Args[%d] = %v, want %v", i, gotArgs[i], tc.wantArgs[i])
}
}
})
}
Expand Down
3 changes: 2 additions & 1 deletion model.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@ func (m *Model) previousPane() {

// editSnippet opens the editor with the selected snippet file path.
func (m *Model) editSnippet() tea.Cmd {
return tea.ExecProcess(editorCmd(m.selectedSnippetFilePath()), func(err error) tea.Msg {
cmd := editorCmd(m.config.Editor, m.selectedSnippetFilePath())
return tea.ExecProcess(cmd, func(err error) tea.Msg {
return updateContentMsg(m.selectedSnippet())
})
}
Expand Down

0 comments on commit a477327

Please sign in to comment.