Skip to content

Commit

Permalink
feat: improve editor open at line (#26)
Browse files Browse the repository at this point in the history
* feat: improve editor open at line

refs  #17

* fix: improve code

* test: fix option name

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
  • Loading branch information
caarlos0 authored Dec 15, 2023
1 parent eff2bbb commit 7ba2b45
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 25 deletions.
59 changes: 34 additions & 25 deletions editor/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,60 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)

const defaultEditor = "nano"

// Get editors that have support for the `+[line number]` flag
// to edit the file at the current line that is in the pager
func getEditorsWithLineNumberSupport() []string {
return []string{
"vi",
"vim",
"nvim",
"nano",
}
}
// Option defines an editor option.
//
// An Option may act differently in some editors, or not be supported in
// some of them.
type Option func(editor, filename string) (args []string, pathInArgs bool)

func hasLineNumberSupport(editor string) bool {
for _, supportedEditor := range getEditorsWithLineNumberSupport() {
if editor == supportedEditor {
return true
// OpenAtLine opens the file at the given line number in supported editors.
func OpenAtLine(number uint) Option {
plusLineEditors := []string{"vi", "vim", "nvim", "nano"}
return func(editor, filename string) ([]string, bool) {
for _, e := range plusLineEditors {
if editor == e {
return []string{fmt.Sprintf("+%d", number)}, false
}
}
if editor == "code" {
return []string{
"--goto",
fmt.Sprintf("%s:%d", filename, number),
}, true
}
return nil, false
}
return false
}

// Cmd returns a *exec.Cmd editing the given path with $EDITOR or nano if no
// $EDITOR is set.
func Cmd(app, path string, lineNumber_optional ...uint) (*exec.Cmd, error) {
func Cmd(app, path string, options ...Option) (*exec.Cmd, error) {
if os.Getenv("SNAP_REVISION") != "" {
return nil, fmt.Errorf("Did you install with Snap? %[1]s is sandboxed and unable to open an editor. Please install %[1]s with Go or another package manager to enable editing.", app)
}

editor, args := getEditor()
editorName := filepath.Base(editor)

// Add line number to open the editor at if provided and a supported editor is being used
if len(lineNumber_optional) == 1 && hasLineNumberSupport(editor) {
lineNumber := lineNumber_optional[0]

lineNumberArg := fmt.Sprintf("+%d", lineNumber)
// Insert line position arg before file name and other flags (required for nano)
args = append([]string{lineNumberArg}, args...)

needsToAppendPath := true
for _, opt := range options {
optArgs, pathInArgs := opt(editorName, path)
if pathInArgs {
needsToAppendPath = false
}
args = append(args, optArgs...)
}
if needsToAppendPath {
args = append(args, path)
}

return exec.Command(editor, append(args, path)...), nil
return exec.Command(editor, args...), nil
}

func getEditor() (string, []string) {
Expand Down
20 changes: 20 additions & 0 deletions editor/editor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ func TestEditor(t *testing.T) {
})
}

t.Run("with line number", func(t *testing.T) {
for k, v := range map[string][]string{
"": {"nano", "+12", filename},
"nvim": {"nvim", "+12", filename},
"vim": {"vim", "+12", filename},
"vscode --foo": {"vscode", "--foo", filename},
"nvim -a -b": {"nvim", "-a", "-b", "+12", filename},
"code --foo": {"code", "--foo", "--goto", filename + ":12"},
} {
t.Run(k, func(t *testing.T) {
t.Setenv("EDITOR", k)
cmd, _ := Cmd("X", "README.md", OpenAtLine(12))
got := cmd.Args
if !reflect.DeepEqual(got, v) {
t.Fatalf("expected %v; got %v", v, got)
}
})
}
})

t.Run("inside snap", func(t *testing.T) {
t.Setenv("SNAP_REVISION", "10")
got, err := Cmd("X", "foo")
Expand Down

0 comments on commit 7ba2b45

Please sign in to comment.