feat: lazysecrets list prints everything lazysecrets can find, for fzf and editor pickers #70
No files matched your search
+18
-10
@@ -28,9 +28,10 @@ import (
|
|||||||
//
|
//
|
||||||
// lazysecrets list | fzf --ansi --with-nth='2..-3' --accept-nth=-1
|
// lazysecrets list | fzf --ansi --with-nth='2..-3' --accept-nth=-1
|
||||||
//
|
//
|
||||||
// Each line is the kind, the name, the account and the link,
|
// Each line is the kind, the name, why it couldn't be read (empty unless
|
||||||
// tab-separated (all but the name one word each, so even fields split on
|
// it failed), the account and the link, tab-separated: kind, account and
|
||||||
// spaces keep them first and last): the name coloured from the theme,
|
// link are one word each, so even fields split on spaces keep them first
|
||||||
|
// and last two. The name is coloured from the theme,
|
||||||
// with the provider's icon (as in the TUI: --icons, LAZYSECRETS_ICONS,
|
// with the provider's icon (as in the TUI: --icons, LAZYSECRETS_ICONS,
|
||||||
// ui.icons); the link never is.
|
// ui.icons); the link never is.
|
||||||
//
|
//
|
||||||
@@ -42,7 +43,7 @@ func listCmd(providers []provider.Provider, cachePath string, timeout func(provi
|
|||||||
fs := flag.NewFlagSet("list", flag.ContinueOnError)
|
fs := flag.NewFlagSet("list", flag.ContinueOnError)
|
||||||
cached := fs.Bool("cached", false, "only what's cached, and repos: load nothing from Azure or Databricks")
|
cached := fs.Bool("cached", false, "only what's cached, and repos: load nothing from Azure or Databricks")
|
||||||
maxAge := fs.Duration("max-age", 2*time.Minute, "load cached lists older than this again")
|
maxAge := fs.Duration("max-age", 2*time.Minute, "load cached lists older than this again")
|
||||||
format := fs.String("format", "text", "text: kind, name, account and link, tab-separated; json: an object per line")
|
format := fs.String("format", "text", "text: kind, name, error, account and link, tab-separated; json: an object per line")
|
||||||
color := fs.String("color", "always", "colour the names (text): always or never; fzf needs --ansi")
|
color := fs.String("color", "always", "colour the names (text): always or never; fzf needs --ansi")
|
||||||
iconsOn := fs.Bool("icons", withIcons, "put the provider's Nerd Font icon before names (text)")
|
iconsOn := fs.Bool("icons", withIcons, "put the provider's Nerd Font icon before names (text)")
|
||||||
kinds := fs.String("kind", "", "only these kinds, comma-separated: "+strings.Join(listing.Kinds, ", ")+" (vault: also scopes and repo files)")
|
kinds := fs.String("kind", "", "only these kinds, comma-separated: "+strings.Join(listing.Kinds, ", ")+" (vault: also scopes and repo files)")
|
||||||
@@ -75,7 +76,9 @@ func listCmd(providers []provider.Provider, cachePath string, timeout func(provi
|
|||||||
case "text":
|
case "text":
|
||||||
write = func(e listing.Entry) error {
|
write = func(e listing.Entry) error {
|
||||||
// A tab or line break in a name would break the line up.
|
// A tab or line break in a name would break the line up.
|
||||||
_, err := fmt.Fprintf(out, "%s\t%s\t%s\t%s\n", e.Kind, oneLine.Replace(nameOf(e, theme, iconSet, *color == "always")), e.Account, e.Link)
|
name := nameOf(e, theme, iconSet, *color == "always")
|
||||||
|
why := errorOf(e, theme, *color == "always")
|
||||||
|
_, err := fmt.Fprintf(out, "%s\t%s\t%s\t%s\t%s\n", e.Kind, oneLine.Replace(name), oneLine.Replace(why), e.Account, e.Link)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
@@ -126,9 +129,17 @@ func listCmd(providers []provider.Provider, cachePath string, timeout func(provi
|
|||||||
|
|
||||||
var oneLine = strings.NewReplacer("\t", " ", "\r\n", " ", "\n", " ", "\r", " ")
|
var oneLine = strings.NewReplacer("\t", " ", "\r\n", " ", "\n", " ", "\r", " ")
|
||||||
|
|
||||||
|
// errorOf is why a list couldn't be read, or "": with colour, a red ✗
|
||||||
|
// before it, as the TUI marks lists it can't read.
|
||||||
|
func errorOf(e listing.Entry, theme styles.Styles, color bool) string {
|
||||||
|
if e.Error == "" || !color {
|
||||||
|
return e.Error
|
||||||
|
}
|
||||||
|
return theme.Error.Render("✗ " + e.Error)
|
||||||
|
}
|
||||||
|
|
||||||
// nameOf is an entry's name for the text format: the provider's icon,
|
// nameOf is an entry's name for the text format: the provider's icon,
|
||||||
// the path with the item's own name standing out, and the account. A
|
// the path with the item's own name standing out, and the account.
|
||||||
// list that couldn't be read has ✗ and why after it.
|
|
||||||
func nameOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, color bool) string {
|
func nameOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, color bool) string {
|
||||||
render := func(st lipgloss.Style, s string) string {
|
render := func(st lipgloss.Style, s string) string {
|
||||||
if !color || s == "" {
|
if !color || s == "" {
|
||||||
@@ -153,8 +164,5 @@ func nameOf(e listing.Entry, theme styles.Styles, iconSet icons.Set, color bool)
|
|||||||
if e.AccountLabel != "" {
|
if e.AccountLabel != "" {
|
||||||
name += render(theme.Muted, " · "+e.AccountLabel)
|
name += render(theme.Muted, " · "+e.AccountLabel)
|
||||||
}
|
}
|
||||||
if e.Error != "" {
|
|
||||||
name += " " + render(theme.Error, "✗ "+e.Error)
|
|
||||||
}
|
|
||||||
return render(theme.Kind(kind), strings.TrimSuffix(icon, " ")) + strings.Repeat(" ", min(len(icon), 1)) + name
|
return render(theme.Kind(kind), strings.TrimSuffix(icon, " ")) + strings.Repeat(" ", min(len(icon), 1)) + name
|
||||||
}
|
}
|
||||||
@@ -26,11 +26,16 @@ func TestListNames(t *testing.T) {
|
|||||||
|
|
||||||
func TestListErrorNames(t *testing.T) {
|
func TestListErrorNames(t *testing.T) {
|
||||||
e := listing.Entry{Provider: "azure", Path: []string{"platform-prod", "kv-restricted"}, Error: "403 Forbidden"}
|
e := listing.Entry{Provider: "azure", Path: []string{"platform-prod", "kv-restricted"}, Error: "403 Forbidden"}
|
||||||
if got := nameOf(e, styles.Default(), icons.NerdFont, false); got != icons.NerdFont.Azure+" platform-prod / kv-restricted ✗ 403 Forbidden" {
|
if got := nameOf(e, styles.Default(), icons.NerdFont, false); got != icons.NerdFont.Azure+" platform-prod / kv-restricted" {
|
||||||
|
t.Errorf("the name has more: %q", got)
|
||||||
|
}
|
||||||
|
if got := errorOf(e, styles.Default(), false); got != "403 Forbidden" {
|
||||||
t.Errorf("plain: %q", got)
|
t.Errorf("plain: %q", got)
|
||||||
}
|
}
|
||||||
red := styles.Default().Error.Render("✗ 403 Forbidden")
|
if got := errorOf(e, styles.Default(), true); got != styles.Default().Error.Render("✗ 403 Forbidden") {
|
||||||
if got := nameOf(e, styles.Default(), icons.NerdFont, true); !strings.HasSuffix(got, red) {
|
t.Errorf("why isn't a red ✗: %q", got)
|
||||||
t.Errorf("why isn't in the error colour: %q", got)
|
}
|
||||||
|
if got := errorOf(listing.Entry{}, styles.Default(), true); got != "" {
|
||||||
|
t.Errorf("no error: %q", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user