lockbox

password manager
Log | Files | Refs | README | LICENSE

commit ea14b905e4032103db269874e3c273b7faf006e9
parent 992ecae8bc27d63460c90eb7640f30253ec7bd69
Author: Sean Enck <sean@ttypty.com>
Date:   Sun,  3 Sep 2023 15:50:34 -0400

support completions that can be filtered to function as well

Diffstat:
Minternal/app/completions.go | 37++++++++++++++++++++++++++++++-------
Minternal/app/completions_test.go | 41++++++++++++++++++++++++++++++++++-------
Minternal/app/doc/shell | 4++++
3 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/internal/app/completions.go b/internal/app/completions.go @@ -3,6 +3,7 @@ package app import ( "bytes" + "errors" "fmt" "strings" "text/template" @@ -82,8 +83,10 @@ func (p Profile) TOTPSubCommands() []string { return totp } -func loadProfiles(exe string) []Profile { +func loadProfiles(exe string, canFilter bool) []Profile { profiles := config.LoadCompletionProfiles() + filter := config.EnvCompletion.Get() + hasFilter := filter != "" && canFilter var res []Profile for _, p := range profiles { name := p.Name @@ -97,6 +100,19 @@ func loadProfiles(exe string) []Profile { n.ReadOnly = !p.Write n.IsDefault = p.Default n.env = p.Env + if hasFilter { + skipped := false + if p.Default { + skipped = filter != "DEFAULT" + } else { + if filter != n.Display() { + skipped = true + } + } + if skipped { + continue + } + } res = append(res, n) } return res @@ -106,7 +122,7 @@ func loadProfiles(exe string) []Profile { func GenerateCompletions(isBash, isHelp bool, exe string) ([]string, error) { if isHelp { var h []string - for _, p := range loadProfiles(exe) { + for _, p := range loadProfiles(exe, false) { if p.IsDefault { continue } @@ -159,11 +175,18 @@ export %s=<unknown> if err != nil { return nil, err } - c.Profiles = loadProfiles(exe) - for _, p := range c.Profiles { - if p.IsDefault { - c.DefaultProfile = p - break + c.Profiles = loadProfiles(exe, true) + switch len(c.Profiles) { + case 0: + return nil, errors.New("no profiles loaded, invalid environment setting?") + case 1: + c.DefaultProfile = c.Profiles[0] + default: + for _, p := range c.Profiles { + if p.IsDefault { + c.DefaultProfile = p + break + } } } shell, err := templateScript(shellScript, c) diff --git a/internal/app/completions_test.go b/internal/app/completions_test.go @@ -1,29 +1,56 @@ package app_test import ( + "fmt" + "os" "testing" "github.com/enckse/lockbox/internal/app" ) -func TestBashCompletion(t *testing.T) { - v, err := app.GenerateCompletions(true, false, "lb") +func TestCompletions(t *testing.T) { + testCompletion(t, true) + testCompletion(t, false) +} + +func testCompletion(t *testing.T, bash bool) { + v, err := app.GenerateCompletions(bash, true, "lb") if err != nil { t.Errorf("invalid error: %v", err) } - if len(v) != 1 { + if len(v) < 2 { t.Errorf("invalid result") } -} - -func TestZshCompletion(t *testing.T) { - v, err := app.GenerateCompletions(false, false, "lb") + defer os.Clearenv() + os.Setenv("LOCKBOX_COMPLETION_FUNCTION", "A") + o, err := app.GenerateCompletions(bash, true, "lb") + if err != nil { + t.Errorf("invalid error: %v", err) + } + if len(o) < 2 || len(o) != len(v) { + t.Errorf("invalid result") + } + os.Setenv("LOCKBOX_COMPLETION_FUNCTION", "") + v, err = app.GenerateCompletions(bash, false, "lb") if err != nil { t.Errorf("invalid error: %v", err) } if len(v) != 1 { t.Errorf("invalid result") } + os.Setenv("LOCKBOX_COMPLETION_FUNCTION", "ZZZ") + _, err = app.GenerateCompletions(bash, false, "lb") + if err == nil || err.Error() != "no profiles loaded, invalid environment setting?" { + t.Errorf("invalid error: %v", err) + } + os.Setenv("LOCKBOX_COMPLETION_FUNCTION", "NOCLIP-READONLY") + n, err := app.GenerateCompletions(bash, false, "lb") + if err != nil { + t.Errorf("invalid error: %v", err) + } + if fmt.Sprintf("%v", n) == fmt.Sprintf("%v", v) { + t.Errorf("invalid result, should filter") + } } func TestProfileDisplay(t *testing.T) { diff --git a/internal/app/doc/shell b/internal/app/doc/shell @@ -1,4 +1,7 @@ _{{ $.Executable }}() { +{{- if eq (len $.Profiles) 1 }} + {{ $.DefaultProfile.Name }} +{{- else}} case "{{ $.CompletionEnv }}" in {{- range $idx, $profile := $.Profiles }} {{- if not $profile.IsDefault }} @@ -11,4 +14,5 @@ _{{ $.Executable }}() { {{ $.DefaultProfile.Name }} ;; esac +{{- end}} }