Compare commits

3 Commits
Author SHA1 Message Date
keb 3eb88689fa fix: a wrapped value in the details keeps its colour on every line
CI / Checks (pull_request) Successful in 35s
PR title / Conventional title (pull_request) Successful in 2s
2026-10-14 21:23:07 +02:00
keb e825a51b30 fix: local builds are dev-<commit> again, not a Go pseudo-version (#68)
Go now stamps local builds with a module pseudo-version (v0.1.3-0.20261014174204-1c31a75d0507+dirty), so the version showed that instead of dev-<commit> as the docs say. The update check also took it for a pre-release of 0.1.3, a version that doesn't exist, rather than a development build. A pseudo-version is now dev-<its commit>, -dirty with uncommitted changes; real versions are unchanged.

Reviewed-on: #68
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
2026-10-14 21:23:06 +02:00
keb 4480e8fed0 fix: lazysecrets starts from fzf's become, on a non-blocking terminal (#67)
fzf's become hands lazysecrets its /dev/tty still non-blocking. Go can't poll /dev/tty on macOS, so it reads it directly, and the TUI's first read failed with "resource temporarily unavailable" (EAGAIN). lazysecrets now makes a terminal on stdin blocking before the TUI starts (Unix; nothing on Windows).

Reviewed-on: #67
Co-authored-by: Karl-Einar Bergstrøm <karl-einarb@outlook.com>
2026-10-14 21:22:19 +02:00
7 changed files with 104 additions and 3 deletions

No files matched your search

+1
View File
@@ -436,6 +436,7 @@ Flags:
Styles: &theme, Styles: &theme,
DefaultFg: defaultFg, DefaultFg: defaultFg,
}) })
blockingStdin()
p = tea.NewProgram(m) p = tea.NewProgram(m)
final, err := p.Run() final, err := p.Run()
if fm, ok := final.(app.Model); ok { if fm, ok := final.(app.Model); ok {
+5
View File
@@ -0,0 +1,5 @@
//go:build !unix
package main
func blockingStdin() {}
+20
View File
@@ -0,0 +1,20 @@
//go:build unix
package main
import (
"os"
"syscall"
"golang.org/x/term"
)
// blockingStdin makes a terminal on stdin blocking again. fzf's become
// hands on its /dev/tty non-blocking; Go can't poll /dev/tty on macOS,
// so it reads it directly, and the TUI's first read would fail with
// EAGAIN ("resource temporarily unavailable").
func blockingStdin() {
if fd := int(os.Stdin.Fd()); term.IsTerminal(fd) {
_ = syscall.SetNonblock(fd, false)
}
}
+20 -2
View File
@@ -1,6 +1,10 @@
package main package main
import "runtime/debug" import (
"regexp"
"runtime/debug"
"strings"
)
// version is set by release builds: // version is set by release builds:
// //
@@ -8,7 +12,12 @@ import "runtime/debug"
var version string var version string
// versionString is the release version, or for other builds what Go // versionString is the release version, or for other builds what Go
// recorded: the module version (go install …@v1.2.3), else the commit. // recorded: the module version (go install …@v1.2.3), else the commit
// (dev-c1a4f90, -dirty with changes not committed).
// pseudo matches a Go pseudo-version (v0.1.3-0.20261014174204-1c31a75d0507,
// maybe +dirty): its commit.
var pseudo = regexp.MustCompile(`[-.]\d{14}-([0-9a-f]{12})(\+.*)?$`)
func versionString() string { func versionString() string {
if version != "" { if version != "" {
return version return version
@@ -18,6 +27,15 @@ func versionString() string {
return "dev" return "dev"
} }
if v := bi.Main.Version; v != "" && v != "(devel)" { if v := bi.Main.Version; v != "" && v != "(devel)" {
// A commit, not a release: a local build (Go stamps those too) or
// go install …@<commit>.
if m := pseudo.FindStringSubmatch(v); m != nil {
dirty := ""
if strings.HasSuffix(v, "+dirty") {
dirty = "-dirty"
}
return "dev-" + m[1][:7] + dirty
}
return v return v
} }
var rev, dirty string var rev, dirty string
+22
View File
@@ -0,0 +1,22 @@
package main
import "testing"
func TestPseudoVersions(t *testing.T) {
for v, want := range map[string]string{
"v0.1.3-0.20261014174204-1c31a75d0507": "1c31a75d0507",
"v0.1.3-0.20261014174204-1c31a75d0507+dirty": "1c31a75d0507",
"v0.0.0-20261014174204-1c31a75d0507": "1c31a75d0507",
"v0.2.0-rc.1.0.20261014174204-1c31a75d0507": "1c31a75d0507",
"v0.1.2": "",
"v0.2.0-rc.1": "",
} {
got := ""
if m := pseudo.FindStringSubmatch(v); m != nil {
got = m[1]
}
if got != want {
t.Errorf("%s: %q, want %q", v, got, want)
}
}
}
+19 -1
View File
@@ -180,6 +180,24 @@ func (d Detail) View(st styles.Styles, focused bool, spin string) string {
const spinnerPlaceholder = "\x00spin\x00" const spinnerPlaceholder = "\x00spin\x00"
// carryStyle starts each wrapped line with the styles still on at the end
// of the line before: a styled value wrapped in the middle (a long ref)
// would go on unstyled, as each line is drawn on its own.
func carryStyle(lines []string) []string {
var on string
for i, line := range lines {
lines[i] = on + line
for _, code := range sgr.FindAllString(line, -1) {
if code == "\x1b[m" || code == "\x1b[0m" {
on = ""
} else {
on += code
}
}
}
return lines
}
// lines renders the body, wrapped to the pane width. // lines renders the body, wrapped to the pane width.
func (d Detail) lines(st styles.Styles) []string { func (d Detail) lines(st styles.Styles) []string {
inner := max(1, d.w-3) inner := max(1, d.w-3)
@@ -187,7 +205,7 @@ func (d Detail) lines(st styles.Styles) []string {
field := func(label, value string) { field := func(label, value string) {
prefix := " " + st.Label.Render(fmt.Sprintf("%-10s", label)) + " " prefix := " " + st.Label.Render(fmt.Sprintf("%-10s", label)) + " "
indent := strings.Repeat(" ", 12) indent := strings.Repeat(" ", 12)
wrapped := strings.Split(ansi.Hardwrap(value, max(1, inner-11), true), "\n") wrapped := carryStyle(strings.Split(ansi.Hardwrap(value, max(1, inner-11), true), "\n"))
out = append(out, prefix+wrapped[0]) out = append(out, prefix+wrapped[0])
for _, w := range wrapped[1:] { for _, w := range wrapped[1:] {
out = append(out, indent+w) out = append(out, indent+w)
+17
View File
@@ -0,0 +1,17 @@
package panes
import (
"strings"
"testing"
)
func TestWrappedValueKeepsItsStyle(t *testing.T) {
red := "\x1b[31m"
got := carryStyle([]string{red + "@Microsoft.KeyVault(SecretUri=https://kv", "-app-prod.vault.azure.net/secrets/x)\x1b[m", "after"})
if !strings.HasPrefix(got[1], red) {
t.Errorf("the wrapped line lost the style: %q", got[1])
}
if strings.HasPrefix(got[2], red) {
t.Errorf("the style went on past its reset: %q", got[2])
}
}