feat: start sops edit on the key's line
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c29319b821
commit
10c2362482
3 files changed
+49
-5
No files matched your search
+3
-1
@@ -77,7 +77,9 @@ KMS, PGP). When sops can't decrypt, its whole error message is shown.
|
|||||||
without either, in the system's default app for the file.
|
without either, in the system's default app for the file.
|
||||||
|
|
||||||
Editors that take a line (vim, nvim, nano, emacs, micro, helix, VS Code,
|
Editors that take a line (vim, nvim, nano, emacs, micro, helix, VS Code,
|
||||||
Zed, Sublime and others) start on the key.
|
Zed, Sublime and others) start on the key. With `sops edit` that works for
|
||||||
|
editors taking `+N` (vim, nvim, nano, emacs, micro and others), and needs
|
||||||
|
sops 3.8 or later.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
|||||||
+27
-4
@@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -71,6 +72,12 @@ func (m *Model) edit() tea.Cmd {
|
|||||||
if f.Sops != "" {
|
if f.Sops != "" {
|
||||||
cmd := exec.Command(f.Sops, "edit", f.Path)
|
cmd := exec.Command(f.Sops, "edit", f.Path)
|
||||||
cmd.Dir = filepath.Dir(f.Path) // sops looks for .sops.yaml from here
|
cmd.Dir = filepath.Dir(f.Path) // sops looks for .sops.yaml from here
|
||||||
|
// sops starts SOPS_EDITOR (else EDITOR, else vim) on the decrypted
|
||||||
|
// copy, which keeps the file's lines: start it on the key.
|
||||||
|
editor := cmp.Or(m.getenv("SOPS_EDITOR"), m.getenv("EDITOR"), "vim")
|
||||||
|
if at, ok := editorAtLine(editor, f.Line); ok {
|
||||||
|
cmd.Env = append(os.Environ(), "SOPS_EDITOR="+at)
|
||||||
|
}
|
||||||
m.flash = flash{}
|
m.flash = flash{}
|
||||||
return tea.ExecProcess(cmd, finished)
|
return tea.ExecProcess(cmd, finished)
|
||||||
}
|
}
|
||||||
@@ -100,6 +107,22 @@ func (m *Model) edit() tea.Cmd {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// plusLine are editors that open at a line with +N before the file.
|
||||||
|
var plusLine = map[string]bool{
|
||||||
|
"vi": true, "vim": true, "nvim": true, "nano": true, "emacs": true, "emacsclient": true,
|
||||||
|
"micro": true, "kak": true, "mg": true, "ne": true, "joe": true, "vis": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// editorAtLine is editor starting at line, for editors that take +N:
|
||||||
|
// sops adds the file after it.
|
||||||
|
func editorAtLine(editor string, line int) (string, bool) {
|
||||||
|
fields := strings.Fields(editor)
|
||||||
|
if line == 0 || len(fields) == 0 || !plusLine[filepath.Base(fields[0])] {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return editor + " +" + strconv.Itoa(line), true
|
||||||
|
}
|
||||||
|
|
||||||
// editorArgs opens f at its line, for editors known to take one.
|
// editorArgs opens f at its line, for editors known to take one.
|
||||||
func editorArgs(editor string, f provider.File) []string {
|
func editorArgs(editor string, f provider.File) []string {
|
||||||
fields := strings.Fields(editor)
|
fields := strings.Fields(editor)
|
||||||
@@ -107,12 +130,12 @@ func editorArgs(editor string, f provider.File) []string {
|
|||||||
return []string{f.Path}
|
return []string{f.Path}
|
||||||
}
|
}
|
||||||
at := f.Path + ":" + strconv.Itoa(f.Line)
|
at := f.Path + ":" + strconv.Itoa(f.Line)
|
||||||
switch filepath.Base(fields[0]) {
|
switch base := filepath.Base(fields[0]); {
|
||||||
case "vi", "vim", "nvim", "nano", "emacs", "emacsclient", "micro", "kak", "mg", "ne", "joe", "vis":
|
case plusLine[base]:
|
||||||
return []string{"+" + strconv.Itoa(f.Line), f.Path}
|
return []string{"+" + strconv.Itoa(f.Line), f.Path}
|
||||||
case "hx", "helix", "subl", "zed":
|
case base == "hx" || base == "helix" || base == "subl" || base == "zed":
|
||||||
return []string{at}
|
return []string{at}
|
||||||
case "code", "codium", "cursor", "windsurf":
|
case base == "code" || base == "codium" || base == "cursor" || base == "windsurf":
|
||||||
return []string{"-g", at}
|
return []string{"-g", at}
|
||||||
}
|
}
|
||||||
return []string{f.Path}
|
return []string{f.Path}
|
||||||
|
|||||||
@@ -323,3 +323,22 @@ func TestEditorArgs(t *testing.T) {
|
|||||||
t.Errorf("no line: %q", got)
|
t.Errorf("no line: %q", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEditorAtLine(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
for _, c := range []struct {
|
||||||
|
editor string
|
||||||
|
line int
|
||||||
|
want string
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"nvim", 4, "nvim +4", true},
|
||||||
|
{"/usr/bin/vim -p", 4, "/usr/bin/vim -p +4", true},
|
||||||
|
{"code --wait", 4, "", false}, // sops adds the file last: no -g file:N
|
||||||
|
{"nvim", 0, "", false},
|
||||||
|
} {
|
||||||
|
if got, ok := editorAtLine(c.editor, c.line); got != c.want || ok != c.ok {
|
||||||
|
t.Errorf("%q at %d: %q %v", c.editor, c.line, got, ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user