diff --git a/docs/config.md b/docs/config.md index 97caa96..0d66fab 100644 --- a/docs/config.md +++ b/docs/config.md @@ -2,9 +2,9 @@ Optional, at `~/.config/lazysecrets/config.yaml` (or `$XDG_CONFIG_HOME/lazysecrets/config.yaml`, or `--config`). Flags override -it. Unknown keys are an error, so typos don't go unnoticed. `E` in -lazysecrets opens it in your editor (making it if it isn't there yet); -changes apply when lazysecrets starts again. +it. Unknown keys are an error, so typos don't go unnoticed. `e` on the +status pane (`0`) opens it in your editor, as in lazygit (making it if +it isn't there yet); changes apply when lazysecrets starts again. ```yaml icons: true # Nerd Font icons (v3+); also --icons=false or LAZYSECRETS_ICONS=0 diff --git a/docs/keys.md b/docs/keys.md index b69d1b0..c078a48 100644 --- a/docs/keys.md +++ b/docs/keys.md @@ -59,7 +59,6 @@ match case exactly. | `x` | [custom commands](custom-commands.md) | | `L` | sign in again (shown when a login has expired) | | `U` | a newer lazysecrets: its changelog, and update in place (restart to use it); or look for one | -| `E` | edit your [config](config.md), like `e` opens a file (made if it isn't there yet; restart to use it) | A revealed value is shown as it reads best: JSON indented, and PEM certificates as their subject, issuer, dates, names and thumbprint, with @@ -123,7 +122,8 @@ Secrets. Going into it (`l`, or `4`) keeps it on that; there `j`/`k`, it's hidden. On top, the status pane (`0`) shows the version, a newer release and how -your accounts are doing. Focused, the right pane lists more under the +your accounts are doing; `e` there opens your [config](config.md) in your +editor, as in lazygit. Focused, the right pane lists more under the logo (when there's room): the version and updates (`U`), each account (`L` on one that needs it signs in), what's expiring (`enter` goes to it), this session's errors, newest first (what a pane showed, or the diff --git a/internal/ui/app/app.go b/internal/ui/app/app.go index d176a53..9deebef 100644 --- a/internal/ui/app/app.go +++ b/internal/ui/app/app.go @@ -965,8 +965,6 @@ func (m *Model) handleKey(msg tea.KeyPressMsg) (cmd tea.Cmd, quit bool) { return m.refresh(), false case key.Matches(msg, k.Update): return m.update(), false - case key.Matches(msg, k.EditConfig): - return m.editConfig(), false } return nil, false } diff --git a/internal/ui/app/edit.go b/internal/ui/app/edit.go index dc95941..b3f9db9 100644 --- a/internal/ui/app/edit.go +++ b/internal/ui/app/edit.go @@ -17,7 +17,7 @@ import ( "git.kebcloud.no/keb/lazysecrets/internal/update" ) -// Opening a repo's file (e): SOPS files with sops edit, which decrypts +// Opening a repo's file (e), or on the status pane the config: SOPS files with sops edit, which decrypts // them for the editor and encrypts them again after. Other files, inside // nvim: in that nvim, once lazysecrets has quit; else in $VISUAL or // $EDITOR, coming back after; else in the system's default app. On a @@ -47,6 +47,8 @@ func (m *Model) edit() tea.Cmd { var c provider.Container var o *provider.Object switch m.focus { + case paneStatus: // like lazygit's status panel + return m.editConfig() case paneSources: m.flash = warning("select a file to open it") return nil @@ -100,7 +102,7 @@ func (m *Model) edit() tea.Cmd { const configHeader = "# lazysecrets config: " + update.DefaultRepo + "/src/branch/main/docs/config.md\n" // editConfig opens the user's config file (the first of them), as e -// opens a file, making it if it isn't there yet. +// opens a file, making it if it isn't there yet: e on the status pane. func (m *Model) editConfig() tea.Cmd { if len(m.configFiles) == 0 { m.flash = warning("no config file") diff --git a/internal/ui/app/help.go b/internal/ui/app/help.go index a405f91..0dfa1ed 100644 --- a/internal/ui/app/help.go +++ b/internal/ui/app/help.go @@ -54,7 +54,8 @@ func (c contextHelp) ShortHelp() []key.Binding { switch { case c.focus == paneStatus: details := key.NewBinding(key.WithKeys(k.Enter.Keys()...), key.WithHelp(k.Enter.Help().Key, "details")) - return append(b, details, k.Update, k.Help, k.Quit) + config := key.NewBinding(key.WithKeys(k.Edit.Keys()...), key.WithHelp(k.Edit.Help().Key, "edit config")) + return append(b, details, config, k.Update, k.Help, k.Quit) case c.focus == paneDetail && c.account && c.of == paneStatus: open := key.NewBinding(key.WithKeys(k.Open.Keys()...), key.WithHelp(k.Open.Help().Key, "open link")) return append(b, k.Up, k.Down, copyField, open, k.Edit, k.Filter, k.Help, k.Quit) diff --git a/internal/ui/app/repo_test.go b/internal/ui/app/repo_test.go index 4ecc742..248b799 100644 --- a/internal/ui/app/repo_test.go +++ b/internal/ui/app/repo_test.go @@ -350,8 +350,9 @@ func TestEditConfig(t *testing.T) { d := newDriverOpts(t, Options{ConfigFiles: []string{path}, OpenURL: func(u string) error { opened = append(opened, u); return nil }}) d.m.getenv = func(string) string { return "" } - // No editor: the system's default app, on a config made for it. - d.keys("E") + // e on the status pane. No editor: the system's default app, on a + // config made for it. + d.keys("0", "e") if !slices.Equal(opened, []string{path}) { t.Errorf("opened %q", opened) } @@ -382,3 +383,12 @@ func TestEditConfig(t *testing.T) { t.Errorf("flash %q", d.m.flash.text) } } + +func TestStatusFooterEditsConfig(t *testing.T) { + t.Parallel() + d := newDriver(t) + d.keys("0") + if !strings.Contains(d.screen(), "e edit config") { + t.Errorf("no edit config in the footer:\n%s", d.screen()) + } +} diff --git a/internal/ui/keys/keys.go b/internal/ui/keys/keys.go index 21a392d..38e86cc 100644 --- a/internal/ui/keys/keys.go +++ b/internal/ui/keys/keys.go @@ -48,7 +48,7 @@ type Map struct { SplitLeft, SplitRight, SplitReset key.Binding Taller, Shorter, ZoomIn, ZoomOut key.Binding Login, Refresh, Help, Quit key.Binding - Update, EditConfig key.Binding + Update key.Binding // filter AcceptFilter, ClearFilter key.Binding FilterUp, FilterDown key.Binding @@ -114,7 +114,7 @@ func (m *Map) Actions() []Action { a(Lists, "copyReference", &m.CopyRef, "copy reference", "secrets", "Copy the reference to use in config, e.g. @Microsoft.KeyVault(SecretUri=…) or {{secrets/scope/key}}."), a(Lists, "versions", &m.Versions, "versions", "secrets", "List the versions of the selected item (Azure). Reveal, copy and share then act on the selected version."), a(Lists, "openInBrowser", &m.Open, "open in browser", "secrets", "Open the selected subscription, vault or item in the browser (Azure portal or Databricks workspace)."), - a(Lists, "edit", &m.Edit, "open file", "secrets", "Open the selected SOPS or .env file, or the file of the selected secret at its line. SOPS files open with sops edit. Others open in the nvim lazysecrets runs in (quitting lazysecrets), else in $VISUAL or $EDITOR, else in the system's default app."), + a(Lists, "edit", &m.Edit, "open file", "secrets", "Open the selected SOPS or .env file, or the file of the selected secret at its line; on the status pane, your config (made if it isn't there yet). SOPS files open with sops edit. Others open in the nvim lazysecrets runs in (quitting lazysecrets), else in $VISUAL or $EDITOR, else in the system's default app."), a(Lists, "share", &m.Share, "copy link", "share", "Copy a lazysecrets:// link to the selected subscription, workspace, vault, scope or secret, for sharing. From the versions view the link is pinned to that version."), a(Lists, "shareMenu", &m.ShareMenu, "share", "share", "Choose what to share: the lazysecrets link, the plain Key Vault URL, the config reference, or the web page."), @@ -131,7 +131,6 @@ func (m *Map) Actions() []Action { a(Lists, "refresh", &m.Refresh, "refresh", "other", "Reload the focused pane, bypassing the cache."), a(Lists, "login", &m.Login, "sign in", "other", "Sign in again (az login or databricks auth login) when a login has expired."), a(Lists, "update", &m.Update, "update", "other", "Check for a newer lazysecrets: its changelog, and update to it."), - a(Lists, "editConfig", &m.EditConfig, "edit config", "other", "Open your config file like e opens a file: in the nvim lazysecrets runs in, else in $VISUAL or $EDITOR, else in the system's default app. Made if it doesn't exist yet. Changes apply when lazysecrets starts again."), a(Lists, "help", &m.Help, "help", "other", "Show this list. Also works in Go to while browsing, and in menus, showing their keys first."), a(Lists, "quit", &m.Quit, "quit", "other", "Quit lazysecrets. ctrl+c always quits too."), @@ -195,7 +194,7 @@ var defaults = map[string][]string{ "lists.dividerLeft": {"ctrl+left", "<"}, "lists.dividerRight": {"ctrl+right", ">"}, "lists.taller": {"ctrl+down", "}"}, "lists.shorter": {"ctrl+up", "{"}, "lists.zoomIn": {"+"}, "lists.zoomOut": {"_"}, "lists.resetLayout": {"="}, - "lists.refresh": {"r"}, "lists.login": {"L"}, "lists.update": {"U"}, "lists.editConfig": {"E"}, "lists.help": {"?"}, "lists.quit": {"q"}, + "lists.refresh": {"r"}, "lists.login": {"L"}, "lists.update": {"U"}, "lists.help": {"?"}, "lists.quit": {"q"}, "filter.down": {"ctrl+j", "ctrl+n", "down"}, "filter.up": {"ctrl+k", "ctrl+p", "up"}, "filter.copyValue": {"ctrl+y"}, "filter.reveal": {"ctrl+r"}, "filter.star": {"ctrl+f"},