commit 404b9c15998d0872510ffbdaed81d2466a8c0cd6
parent f9c91bb1561e6b9becc6e391867e360fdd570ccd
Author: Sean Enck <sean@ttypty.com>
Date: Mon, 9 Jun 2025 15:13:35 -0400
remove conditionals in completions
Diffstat:
6 files changed, 21 insertions(+), 130 deletions(-)
diff --git a/internal/app/completions/core.go b/internal/app/completions/core.go
@@ -11,7 +11,6 @@ import (
"text/template"
"git.sr.ht/~enckse/lockbox/internal/app/commands"
- "git.sr.ht/~enckse/lockbox/internal/config"
)
type (
@@ -35,59 +34,14 @@ type (
HelpAdvancedCommand string
HelpConfigCommand string
ExportCommand string
- Options []CompletionOption
- TOTPSubCommands []CompletionOption
- Conditionals Conditionals
- }
- // Conditionals help control completion flow
- Conditionals struct {
- Not struct {
- ReadOnly string
- Ever string
- }
- Exported []string
- }
- // CompletionOption are conditional wrapped logic for options that may be disabled
- CompletionOption struct {
- Conditional string
- Key string
+ Options []string
+ TOTPSubCommands []string
}
)
//go:embed shell/*
var shell embed.FS
-func (c Template) newGenOptions(defaults []string, kv map[string]string) []CompletionOption {
- opt := []CompletionOption{}
- for _, a := range defaults {
- opt = append(opt, CompletionOption{c.Conditionals.Not.Ever, a})
- }
- var keys []string
- for k := range kv {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- for _, key := range keys {
- check := kv[key]
- opt = append(opt, CompletionOption{check, key})
- }
- return opt
-}
-
-// NewConditionals creates the conditional components of completions
-func NewConditionals() Conditionals {
- const shellIsNotText = `[ "%s" != "%s" ]`
- c := Conditionals{}
- registerIsNotEqual := func(key interface{ Key() string }, right string) string {
- k := key.Key()
- c.Exported = append(c.Exported, k)
- return fmt.Sprintf(shellIsNotText, fmt.Sprintf("$%s", k), right)
- }
- c.Not.ReadOnly = registerIsNotEqual(config.EnvReadOnly, config.YesValue)
- c.Not.Ever = fmt.Sprintf(shellIsNotText, "1", "0")
- return c
-}
-
// Generate handles creating shell completion outputs
func Generate(completionType, exe string) ([]string, error) {
if !slices.Contains(commands.CompletionTypes, completionType) {
@@ -112,16 +66,11 @@ func Generate(completionType, exe string) ([]string, error) {
DoTOTPList: fmt.Sprintf("%s %s %s", exe, commands.TOTP, commands.TOTPList),
ExportCommand: fmt.Sprintf("%s %s %s", exe, commands.Env, commands.Completions),
}
- c.Conditionals = NewConditionals()
- c.Options = c.newGenOptions([]string{commands.Help, commands.List, commands.Show, commands.Version, commands.JSON, commands.Groups, commands.Clip, commands.TOTP},
- map[string]string{
- commands.Move: c.Conditionals.Not.ReadOnly,
- commands.Remove: c.Conditionals.Not.ReadOnly,
- commands.Insert: c.Conditionals.Not.ReadOnly,
- commands.Unset: c.Conditionals.Not.ReadOnly,
- })
- c.TOTPSubCommands = c.newGenOptions([]string{commands.TOTPMinimal, commands.TOTPOnce, commands.TOTPShow, commands.TOTPURL, commands.TOTPSeed, commands.TOTPClip}, nil)
+ c.Options = []string{commands.Help, commands.List, commands.Show, commands.Version, commands.JSON, commands.Groups, commands.Clip, commands.TOTP, commands.Move, commands.Remove, commands.Insert, commands.Unset}
+ c.TOTPSubCommands = []string{commands.TOTPMinimal, commands.TOTPOnce, commands.TOTPShow, commands.TOTPURL, commands.TOTPSeed, commands.TOTPClip}
+ sort.Strings(c.Options)
+ sort.Strings(c.TOTPSubCommands)
using, err := shell.ReadFile(filepath.Join("shell", fmt.Sprintf("%s.sh", completionType)))
if err != nil {
diff --git a/internal/app/completions/core_test.go b/internal/app/completions/core_test.go
@@ -1,14 +1,10 @@
package completions_test
import (
- "fmt"
- "slices"
- "sort"
"strings"
"testing"
"git.sr.ht/~enckse/lockbox/internal/app/completions"
- "git.sr.ht/~enckse/lockbox/internal/reflect"
)
func TestCompletions(t *testing.T) {
@@ -20,29 +16,6 @@ func TestCompletions(t *testing.T) {
}
}
-func TestConditionals(t *testing.T) {
- c := completions.NewConditionals()
- sort.Strings(c.Exported)
- need := []string{"LOCKBOX_READONLY"}
- if len(c.Exported) != len(need) || fmt.Sprintf("%v", c.Exported) != fmt.Sprintf("%v", need) {
- t.Errorf("invalid exports: %v", c.Exported)
- }
- fields := reflect.ListFields(c.Not)
- if len(fields) != len(need)+1 {
- t.Errorf("invalid fields: %v", fields)
- }
- for _, n := range need {
- value := "false"
- switch n {
- case "LOCKBOX_READONLY":
- value = "true"
- }
- if !slices.Contains(fields, fmt.Sprintf(`[ "$%s" != "%s" ]`, n, value)) {
- t.Errorf("needed conditional %s not found: %v", n, fields)
- }
- }
-}
-
func testCompletion(t *testing.T, completionMode, need string) {
v, err := completions.Generate(completionMode, "lb")
if err != nil {
diff --git a/internal/app/completions/shell/bash.sh b/internal/app/completions/shell/bash.sh
@@ -2,13 +2,10 @@
_{{ $.Executable }}() {
local cur opts chosen found
- source <({{ $.ExportCommand }})
cur=${COMP_WORDS[COMP_CWORD]}
if [ "$COMP_CWORD" -eq 1 ]; then
{{- range $idx, $value := $.Options }}
- if {{ $value.Conditional }}; then
- opts="${opts}{{ $value.Key }} "
- fi
+ opts="${opts}{{ $value }} "
{{- end}}
# shellcheck disable=SC2207
COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
@@ -19,10 +16,8 @@ _{{ $.Executable }}() {
chosen=${COMP_WORDS[1]}
found=0
{{- range $idx, $value := $.Options }}
- if {{ $value.Conditional }}; then
- if [ "$chosen" == "{{ $value.Key }}" ]; then
- found=1
- fi
+ if [ "$chosen" == "{{ $value }}" ]; then
+ found=1
fi
{{- end}}
if [ "$found" -eq 0 ]; then
@@ -42,9 +37,7 @@ _{{ $.Executable }}() {
"{{ $.TOTPCommand }}")
opts="{{ $.TOTPListCommand }} "
{{- range $key, $value := .TOTPSubCommands }}
- if {{ $value.Conditional }}; then
- opts="$opts {{ $value.Key }}"
- fi
+ opts="$opts {{ $value }}"
{{- end}}
;;
"{{ $.ShowCommand }}" | "{{ $.JSONCommand }}" | "{{ $.ClipCommand }}")
@@ -60,10 +53,8 @@ _{{ $.Executable }}() {
"{{ $.TOTPCommand }}")
case "${COMP_WORDS[2]}" in
{{- range $key, $value := $.TOTPSubCommands }}
- "{{ $value.Key }}")
- if {{ $value.Conditional }}; then
- opts=$({{ $.DoTOTPList }})
- fi
+ "{{ $value }}")
+ opts=$({{ $.DoTOTPList }})
;;
{{- end}}
esac
diff --git a/internal/app/completions/shell/zsh.sh b/internal/app/completions/shell/zsh.sh
@@ -3,7 +3,6 @@
_{{ $.Executable }}() {
local curcontext="$curcontext" state len chosen found args
typeset -A opt_args
- source <({{ $.ExportCommand }})
_arguments \
'1: :->main'\
'*: :->args'
@@ -13,12 +12,10 @@ _{{ $.Executable }}() {
main)
args=""
{{- range $idx, $value := $.Options }}
- if {{ $value.Conditional }}; then
- if [ -n "$args" ]; then
- args="$args "
- fi
- args="${args}{{ $value.Key }}"
+ if [ -n "$args" ]; then
+ args="$args "
fi
+ args="${args}{{ $value }}"
{{- end }}
_arguments "1:main:($args)"
;;
@@ -29,10 +26,8 @@ _{{ $.Executable }}() {
chosen=$words[2]
found=0
{{- range $idx, $value := $.Options }}
- if {{ $value.Conditional }}; then
- if [[ "$chosen" == "{{ $value.Key }}" ]]; then
- found=1
- fi
+ if [[ "$chosen" == "{{ $value }}" ]]; then
+ found=1
fi
{{- end }}
if [ "$found" -eq 0 ]; then
@@ -67,18 +62,14 @@ _{{ $.Executable }}() {
3)
compadd "$@" {{ $.TOTPListCommand }}
{{- range $key, $value := .TOTPSubCommands }}
- if {{ $value.Conditional }}; then
- compadd "$@" {{ $value.Key }}
- fi
+ compadd "$@" {{ $value }}
{{ end }}
;;
4)
case $words[3] in
{{- range $key, $value := .TOTPSubCommands }}
- "{{ $value.Key }}")
- if {{ $value.Conditional }}; then
- compadd "$@" $({{ $.DoTOTPList }})
- fi
+ "{{ $value }}")
+ compadd "$@" $({{ $.DoTOTPList }})
;;
{{- end}}
esac
diff --git a/internal/app/info.go b/internal/app/info.go
@@ -61,12 +61,7 @@ func info(command string, args []string) ([]string, error) {
switch len(args) {
case 0:
case 1:
- sub := args[0]
- if sub == commands.Completions {
- set = completions.NewConditionals().Exported
- } else {
- set = []string{sub}
- }
+ set = []string{args[0]}
default:
return nil, errors.New("invalid env command, too many arguments")
}
diff --git a/internal/app/info_test.go b/internal/app/info_test.go
@@ -83,14 +83,6 @@ func TestEnvInfo(t *testing.T) {
}
store.SetString("LOCKBOX_READONLY", "true")
buf = bytes.Buffer{}
- ok, err = app.Info(&buf, "vars", []string{"completions"})
- if !ok || err != nil {
- t.Errorf("invalid error: %v", err)
- }
- if strings.TrimSpace(buf.String()) != "LOCKBOX_READONLY=true" {
- t.Error("nothing written")
- }
- buf = bytes.Buffer{}
ok, err = app.Info(&buf, "vars", []string{"LOCKBOX_READONLY"})
if !ok || err != nil {
t.Errorf("invalid error: %v", err)