Compare commits
1
Commits
main
...
386af66565
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
386af66565
|
No files matched your search
@@ -69,11 +69,7 @@ func installHandler(cfg config.Config, configPath, term string) (string, string,
|
|||||||
if _, err := launchCommand(cfg, configPath, term, exe, "lazysecrets://check"); err != nil {
|
if _, err := launchCommand(cfg, configPath, term, exe, "lazysecrets://check"); err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
launch := []string{exe}
|
launch := append(append([]string{exe}, configArgs(configPath)...), "launch")
|
||||||
if configPath != defaultConfigPath() {
|
|
||||||
launch = append(launch, "--config", configPath)
|
|
||||||
}
|
|
||||||
launch = append(launch, "launch")
|
|
||||||
if term != "" {
|
if term != "" {
|
||||||
launch = append(launch, "--terminal", term)
|
launch = append(launch, "--terminal", term)
|
||||||
}
|
}
|
||||||
@@ -188,8 +184,14 @@ func launchCommand(cfg config.Config, configPath, term, exe, link string) ([]str
|
|||||||
// innerCommand runs lazysecrets on link, with the environment it needs.
|
// innerCommand runs lazysecrets on link, with the environment it needs.
|
||||||
func innerCommand(configPath, exe, link string) []string {
|
func innerCommand(configPath, exe, link string) []string {
|
||||||
inner := append(append([]string{"/usr/bin/env"}, linkhandler.Env(os.Getenv)...), exe)
|
inner := append(append([]string{"/usr/bin/env"}, linkhandler.Env(os.Getenv)...), exe)
|
||||||
if configPath != defaultConfigPath() {
|
inner = append(inner, configArgs(configPath)...)
|
||||||
inner = append(inner, "--config", configPath)
|
|
||||||
}
|
|
||||||
return append(inner, "open", link)
|
return append(inner, "open", link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// configArgs passes the config files on, unless they're the default.
|
||||||
|
func configArgs(configPath string) []string {
|
||||||
|
if configPath == defaultConfigPath() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []string{"--config", configPath}
|
||||||
|
}
|
||||||
+47
-64
@@ -177,26 +177,22 @@ Flags:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var open, getRef *ref.Ref
|
sub := "" // the subcommand; "" browses
|
||||||
|
var subArgs []string
|
||||||
|
var open *ref.Ref
|
||||||
|
var getRef ref.Ref
|
||||||
var openAction string
|
var openAction string
|
||||||
var shareArgs, listArgs []string
|
|
||||||
printKeys := false
|
|
||||||
switch args := flag.Args(); {
|
switch args := flag.Args(); {
|
||||||
case len(args) > 0 && args[0] == "share":
|
case len(args) > 0 && (args[0] == "share" || args[0] == "list"):
|
||||||
shareArgs = args[1:]
|
sub, subArgs = args[0], args[1:]
|
||||||
if len(shareArgs) == 0 {
|
|
||||||
shareArgs = []string{} // still sharing: says how
|
|
||||||
}
|
|
||||||
case len(args) > 0 && args[0] == "list":
|
|
||||||
listArgs = append([]string{}, args[1:]...) // not nil: listing
|
|
||||||
case len(args) == 1 && args[0] == "keybindings":
|
case len(args) == 1 && args[0] == "keybindings":
|
||||||
printKeys = true
|
sub = "keybindings"
|
||||||
case len(args) > 0 && args[0] == "get":
|
case len(args) > 0 && args[0] == "get":
|
||||||
r, _, err := refArg("get", args[1:])
|
r, _, err := refArg("get", args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
getRef = &r
|
sub, getRef = "get", r
|
||||||
case len(args) > 0 && args[0] == "handler":
|
case len(args) > 0 && args[0] == "handler":
|
||||||
return handler(*configPath, args[1:])
|
return handler(*configPath, args[1:])
|
||||||
case len(args) > 0 && args[0] == "launch":
|
case len(args) > 0 && args[0] == "launch":
|
||||||
@@ -242,7 +238,7 @@ Flags:
|
|||||||
if err := checkCommandKeys(&keymap, cfg.CustomCommands); err != nil {
|
if err := checkCommandKeys(&keymap, cfg.CustomCommands); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if printKeys {
|
if sub == "keybindings" {
|
||||||
fmt.Print(keymap.YAML())
|
fmt.Print(keymap.YAML())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -270,25 +266,13 @@ Flags:
|
|||||||
}
|
}
|
||||||
// timeoutFor is how long a request to a provider of kind k may take.
|
// timeoutFor is how long a request to a provider of kind k may take.
|
||||||
timeoutFor := func(k provider.Kind) time.Duration { return cmp.Or(timeouts[k], *timeout) }
|
timeoutFor := func(k provider.Kind) time.Duration { return cmp.Or(timeouts[k], *timeout) }
|
||||||
if !set["clipboard-clear"] && cfg.Values.ClipboardClear != nil {
|
if !set["clipboard-clear"] {
|
||||||
*clipClear = *cfg.Values.ClipboardClear
|
*clipClear = valueOr(cfg.Values.ClipboardClear, *clipClear)
|
||||||
}
|
|
||||||
expiryDays := 30
|
|
||||||
if cfg.UI.ExpiryWarningDays != nil {
|
|
||||||
expiryDays = *cfg.UI.ExpiryWarningDays
|
|
||||||
}
|
|
||||||
revealTimeout := 60 * time.Second
|
|
||||||
if cfg.Values.RevealTimeout != nil {
|
|
||||||
revealTimeout = *cfg.Values.RevealTimeout
|
|
||||||
}
|
|
||||||
loadDelay := 150 * time.Millisecond
|
|
||||||
if cfg.UI.LoadDelay != nil {
|
|
||||||
loadDelay = *cfg.UI.LoadDelay
|
|
||||||
}
|
|
||||||
var updateEvery time.Duration // 0: the app's default, a day
|
|
||||||
if cfg.Updates.AutoCheckInterval != nil {
|
|
||||||
updateEvery = *cfg.Updates.AutoCheckInterval
|
|
||||||
}
|
}
|
||||||
|
expiryWarning := time.Duration(valueOr(cfg.UI.ExpiryWarningDays, 30)) * 24 * time.Hour
|
||||||
|
revealTimeout := valueOr(cfg.Values.RevealTimeout, 60*time.Second)
|
||||||
|
loadDelay := valueOr(cfg.UI.LoadDelay, 150*time.Millisecond)
|
||||||
|
updateEvery := valueOr(cfg.Updates.AutoCheckInterval, 0) // 0: the app's default, a day
|
||||||
if !set["icons"] {
|
if !set["icons"] {
|
||||||
switch {
|
switch {
|
||||||
case os.Getenv("LAZYSECRETS_ICONS") != "":
|
case os.Getenv("LAZYSECRETS_ICONS") != "":
|
||||||
@@ -298,7 +282,17 @@ Flags:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recentIcon := cfg.UI.RecentIcon != nil && *cfg.UI.RecentIcon
|
recentIcon := valueOr(cfg.UI.RecentIcon, false)
|
||||||
|
|
||||||
|
startDir := *dir
|
||||||
|
if startDir == "" {
|
||||||
|
startDir, _ = os.Getwd()
|
||||||
|
}
|
||||||
|
// What was loaded last time.
|
||||||
|
cacheFile := ""
|
||||||
|
if d, err := config.CacheDir(); err == nil && !*demo && config.On(cfg.Storage.Cache) {
|
||||||
|
cacheFile = filepath.Join(d, "cache.json")
|
||||||
|
}
|
||||||
|
|
||||||
// Stars, notes and the layout. Demo mode keeps them in memory, so
|
// Stars, notes and the layout. Demo mode keeps them in memory, so
|
||||||
// sample vaults never end up in the real file.
|
// sample vaults never end up in the real file.
|
||||||
@@ -356,17 +350,9 @@ Flags:
|
|||||||
providers = append(providers, dbx)
|
providers = append(providers, dbx)
|
||||||
}
|
}
|
||||||
if config.On(pc.Repos.Enabled) {
|
if config.On(pc.Repos.Enabled) {
|
||||||
start := *dir
|
|
||||||
if start == "" {
|
|
||||||
start, _ = os.Getwd()
|
|
||||||
}
|
|
||||||
roots := repo.DefaultRoots
|
|
||||||
if pc.Repos.Roots != nil {
|
|
||||||
roots = *pc.Repos.Roots
|
|
||||||
}
|
|
||||||
repos := repo.New(repo.Settings{
|
repos := repo.New(repo.Settings{
|
||||||
Dir: start, Paths: pc.Repos.Paths, Roots: roots, Starred: starredRepos(st),
|
Dir: startDir, Paths: pc.Repos.Paths, Roots: valueOr(pc.Repos.Roots, repo.DefaultRoots),
|
||||||
Include: pc.Repos.Include, Exclude: pc.Repos.Exclude,
|
Starred: starredRepos(st), Include: pc.Repos.Include, Exclude: pc.Repos.Exclude,
|
||||||
})
|
})
|
||||||
// The repo it started in (shown on top as Repo) and the
|
// The repo it started in (shown on top as Repo) and the
|
||||||
// others, checked for secret files in the background like
|
// others, checked for secret files in the background like
|
||||||
@@ -382,19 +368,14 @@ Flags:
|
|||||||
// the standard logger, which would draw over the TUI.
|
// the standard logger, which would draw over the TUI.
|
||||||
log.SetOutput(io.Discard)
|
log.SetOutput(io.Discard)
|
||||||
|
|
||||||
if getRef != nil {
|
switch sub {
|
||||||
|
case "get":
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeoutFor(getRef.Kind))
|
ctx, cancel := context.WithTimeout(context.Background(), timeoutFor(getRef.Kind))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
return get(ctx, providers, st, *getRef)
|
return get(ctx, providers, st, getRef)
|
||||||
}
|
case "list":
|
||||||
if listArgs != nil {
|
return listCmd(providers, st, cacheFile, timeoutFor, theme, *icons, recentIcon, expiryWarning, subArgs, os.Stdout)
|
||||||
cachePath := ""
|
case "share":
|
||||||
if d, err := config.CacheDir(); err == nil && !*demo && config.On(cfg.Storage.Cache) {
|
|
||||||
cachePath = filepath.Join(d, "cache.json")
|
|
||||||
}
|
|
||||||
return listCmd(providers, st, cachePath, timeoutFor, theme, *icons, recentIcon, time.Duration(expiryDays)*24*time.Hour, listArgs, os.Stdout)
|
|
||||||
}
|
|
||||||
if shareArgs != nil {
|
|
||||||
// The files from a repo, the key from whichever provider it's
|
// The files from a repo, the key from whichever provider it's
|
||||||
// in: the longest timeout.
|
// in: the longest timeout.
|
||||||
d := *timeout
|
d := *timeout
|
||||||
@@ -403,7 +384,7 @@ Flags:
|
|||||||
}
|
}
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), d)
|
ctx, cancel := context.WithTimeout(context.Background(), d)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
return shareFiles(ctx, providers, st, cfg.Sharing.Key, shareRules(cfg), shareArgs, os.Stdout)
|
return shareFiles(ctx, providers, st, cfg.Sharing.Key, shareRules(cfg), subArgs, os.Stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links opened elsewhere (lazysecrets launch) can come here.
|
// Links opened elsewhere (lazysecrets launch) can come here.
|
||||||
@@ -437,16 +418,10 @@ Flags:
|
|||||||
onActive = srv.Touch
|
onActive = srv.Touch
|
||||||
}
|
}
|
||||||
|
|
||||||
// What was loaded last time, and where it was left in this folder.
|
// Where it was left in this folder.
|
||||||
var cacheFile, placeDir string
|
placeDir := ""
|
||||||
if !*demo {
|
if !*demo {
|
||||||
if d, err := config.CacheDir(); err == nil && config.On(cfg.Storage.Cache) {
|
placeDir = startDir
|
||||||
cacheFile = filepath.Join(d, "cache.json")
|
|
||||||
}
|
|
||||||
placeDir = *dir
|
|
||||||
if placeDir == "" {
|
|
||||||
placeDir, _ = os.Getwd()
|
|
||||||
}
|
|
||||||
if abs, err := filepath.Abs(placeDir); err == nil {
|
if abs, err := filepath.Abs(placeDir); err == nil {
|
||||||
placeDir = abs
|
placeDir = abs
|
||||||
}
|
}
|
||||||
@@ -463,7 +438,7 @@ Flags:
|
|||||||
NoHistory: !config.On(cfg.Storage.History),
|
NoHistory: !config.On(cfg.Storage.History),
|
||||||
OnActive: onActive,
|
OnActive: onActive,
|
||||||
RevealTimeout: revealTimeout,
|
RevealTimeout: revealTimeout,
|
||||||
ExpiryWarning: time.Duration(expiryDays) * 24 * time.Hour,
|
ExpiryWarning: expiryWarning,
|
||||||
HideOnBlur: config.On(cfg.Values.HideOnBlur),
|
HideOnBlur: config.On(cfg.Values.HideOnBlur),
|
||||||
HandlerSetup: setup,
|
HandlerSetup: setup,
|
||||||
Updater: updater(cfg.Updates.Sources),
|
Updater: updater(cfg.Updates.Sources),
|
||||||
@@ -496,6 +471,14 @@ Flags:
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// valueOr is *p, or def when p is nil (not set in the config).
|
||||||
|
func valueOr[T any](p *T, def T) T {
|
||||||
|
if p == nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
// configFiles are the config files given, for the status pane: those
|
// configFiles are the config files given, for the status pane: those
|
||||||
// that exist, or the first if none does (where to create one).
|
// that exist, or the first if none does (where to create one).
|
||||||
func configFiles(list string) []string {
|
func configFiles(list string) []string {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -32,8 +33,12 @@ func updater(servers []string) *app.Updater {
|
|||||||
// updateCmd is lazysecrets update [--check]: the newer release's
|
// updateCmd is lazysecrets update [--check]: the newer release's
|
||||||
// changelog, then (unless --check) install it.
|
// changelog, then (unless --check) install it.
|
||||||
func updateCmd(configPath string, args []string) error {
|
func updateCmd(configPath string, args []string) error {
|
||||||
check := len(args) == 1 && args[0] == "--check"
|
fs := flag.NewFlagSet("update", flag.ContinueOnError)
|
||||||
if len(args) > 0 && !check {
|
check := fs.Bool("check", false, "just say if there's a newer release")
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if fs.NArg() != 0 {
|
||||||
return errors.New("usage: lazysecrets update [--check]")
|
return errors.New("usage: lazysecrets update [--check]")
|
||||||
}
|
}
|
||||||
cfg, err := config.LoadAll(strings.Split(configPath, ","))
|
cfg, err := config.LoadAll(strings.Split(configPath, ","))
|
||||||
@@ -49,14 +54,14 @@ func updateCmd(configPath string, args []string) error {
|
|||||||
return fmt.Errorf("looking for a newer lazysecrets: %w", err)
|
return fmt.Errorf("looking for a newer lazysecrets: %w", err)
|
||||||
}
|
}
|
||||||
if !update.Newer(current, r.Tag) {
|
if !update.Newer(current, r.Tag) {
|
||||||
if !update.Newer(current, "v999.0.0") {
|
if strings.HasPrefix(current, "dev") {
|
||||||
return fmt.Errorf("this is a development build (%s); the latest release is %s: install it with install.sh, or go install …@%s", current, r.Tag, r.Tag)
|
return fmt.Errorf("this is a development build (%s); the latest release is %s: install it with install.sh, or go install …@%s", current, r.Tag, r.Tag)
|
||||||
}
|
}
|
||||||
fmt.Printf("lazysecrets %s is the latest (%s)\n", current, r.Tag)
|
fmt.Printf("lazysecrets %s is the latest (%s)\n", current, r.Tag)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fmt.Printf("lazysecrets %s is out (you have %s):\n\n%s\n\n", r.Tag, current, indent(r.Notes(current)))
|
fmt.Printf("lazysecrets %s is out (you have %s):\n\n%s\n\n", r.Tag, current, indent(r.Notes(current)))
|
||||||
if check {
|
if *check {
|
||||||
fmt.Println("lazysecrets update installs it.")
|
fmt.Println("lazysecrets update installs it.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// version is set by release builds:
|
// version is set by release builds:
|
||||||
@@ -31,7 +30,7 @@ func versionString() string {
|
|||||||
// go install …@<commit>.
|
// go install …@<commit>.
|
||||||
if m := pseudo.FindStringSubmatch(v); m != nil {
|
if m := pseudo.FindStringSubmatch(v); m != nil {
|
||||||
dirty := ""
|
dirty := ""
|
||||||
if strings.HasSuffix(v, "+dirty") {
|
if m[2] != "" {
|
||||||
dirty = "-dirty"
|
dirty = "-dirty"
|
||||||
}
|
}
|
||||||
return "dev-" + m[1][:7] + dirty
|
return "dev-" + m[1][:7] + dirty
|
||||||
|
|||||||
@@ -36,15 +36,18 @@ func Dir(stateDir string) string {
|
|||||||
type Status struct {
|
type Status struct {
|
||||||
PID int `json:"pid"`
|
PID int `json:"pid"`
|
||||||
LastActive time.Time `json:"lastActive"` // last key press or focus
|
LastActive time.Time `json:"lastActive"` // last key press or focus
|
||||||
// Reach is how readily it can be shown: 2 in view (outside tmux, or
|
Reach int `json:"reach"` // how readily it can be shown: unreachable, switchable or inView
|
||||||
// in a tmux session a client shows), 1 in a tmux session that a tmux
|
|
||||||
// client can be switched to, 0 not at all.
|
|
||||||
Reach int `json:"reach"`
|
|
||||||
// App is the terminal app it would show in (macOS), preferring the
|
// App is the terminal app it would show in (macOS), preferring the
|
||||||
// app the link was clicked in.
|
// app the link was clicked in.
|
||||||
App string `json:"app,omitempty"`
|
App string `json:"app,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
unreachable = 0
|
||||||
|
switchable = 1 // in a tmux session that a tmux client can be switched to
|
||||||
|
inView = 2 // outside tmux, or in a tmux session a client shows
|
||||||
|
)
|
||||||
|
|
||||||
type request struct {
|
type request struct {
|
||||||
Op string `json:"op"` // "status" or "open"
|
Op string `json:"op"` // "status" or "open"
|
||||||
Link string `json:"link,omitempty"`
|
Link string `json:"link,omitempty"`
|
||||||
@@ -188,7 +191,7 @@ func Best(found []Found, front string, terminal bool) (Found, bool) {
|
|||||||
best = f
|
best = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return best, best.Reach > 0
|
return best, best.Reach > unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open hands link, clicked in front, to f.
|
// Open hands link, clicked in front, to f.
|
||||||
|
|||||||
+22
-23
@@ -1,6 +1,7 @@
|
|||||||
package instance
|
package instance
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -25,7 +26,8 @@ func tmux(args ...string) (string, error) {
|
|||||||
func inTmux() bool { return os.Getenv("TMUX") != "" && os.Getenv("TMUX_PANE") != "" }
|
func inTmux() bool { return os.Getenv("TMUX") != "" && os.Getenv("TMUX_PANE") != "" }
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
name, session, activity string // activity: Unix seconds
|
name, session string
|
||||||
|
activity int // Unix seconds
|
||||||
pid int
|
pid int
|
||||||
app string
|
app string
|
||||||
}
|
}
|
||||||
@@ -42,30 +44,31 @@ func clients() []client {
|
|||||||
if len(f) < 4 {
|
if len(f) < 4 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pid, err := strconv.Atoi(f[1])
|
activity, err1 := strconv.Atoi(f[0])
|
||||||
if err != nil {
|
pid, err2 := strconv.Atoi(f[1])
|
||||||
|
if err1 != nil || err2 != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cs = append(cs, client{name: f[2], session: f[3], activity: f[0], pid: pid, app: linkhandler.HostApp(pid)})
|
cs = append(cs, client{name: f[2], session: f[3], activity: activity, pid: pid, app: linkhandler.HostApp(pid)})
|
||||||
}
|
}
|
||||||
// Activity has the same width for centuries: strings compare like
|
slices.SortStableFunc(cs, func(a, b client) int { return cmp.Compare(b.activity, a.activity) })
|
||||||
// numbers.
|
|
||||||
slices.SortStableFunc(cs, func(a, b client) int { return strings.Compare(b.activity, a.activity) })
|
|
||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
|
|
||||||
// place is where this instance would show: the tmux client (zero outside
|
// place is where this instance would show: the tmux client (zero outside
|
||||||
// tmux), the app, and reach: 2 already on screen there (outside tmux, or
|
// tmux), the app, and its reach.
|
||||||
// a client on its session), 1 after switching a client, 0 nowhere.
|
|
||||||
func place(front string) (client, string, int) {
|
func place(front string) (client, string, int) {
|
||||||
if !inTmux() {
|
if !inTmux() {
|
||||||
return client{}, linkhandler.HostApp(os.Getpid()), 2
|
return client{}, linkhandler.HostApp(os.Getpid()), inView
|
||||||
}
|
}
|
||||||
session, err := tmux("display-message", "-p", "-t", os.Getenv("TMUX_PANE"), "#{session_name}")
|
session, err := tmux("display-message", "-p", "-t", os.Getenv("TMUX_PANE"), "#{session_name}")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return client{}, "", 0
|
return client{}, "", unreachable
|
||||||
}
|
}
|
||||||
cs := clients()
|
cs := clients()
|
||||||
|
if len(cs) == 0 {
|
||||||
|
return client{}, "", unreachable
|
||||||
|
}
|
||||||
// Best first: in the front app on its session, in the front app,
|
// Best first: in the front app on its session, in the front app,
|
||||||
// on its session, any.
|
// on its session, any.
|
||||||
rank := func(c client) int {
|
rank := func(c client) int {
|
||||||
@@ -78,20 +81,16 @@ func place(front string) (client, string, int) {
|
|||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
var best client
|
best := cs[0]
|
||||||
found := false
|
for _, c := range cs[1:] {
|
||||||
for _, c := range cs {
|
if rank(c) > rank(best) {
|
||||||
if !found || rank(c) > rank(best) {
|
best = c
|
||||||
best, found = c, true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
|
||||||
return client{}, "", 0
|
|
||||||
}
|
|
||||||
if best.session == session {
|
if best.session == session {
|
||||||
return best, best.app, 2
|
return best, best.app, inView
|
||||||
}
|
}
|
||||||
return best, best.app, 1
|
return best, best.app, switchable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raise brings this instance into view for a link clicked in front: in
|
// Raise brings this instance into view for a link clicked in front: in
|
||||||
@@ -99,14 +98,14 @@ func place(front string) (client, string, int) {
|
|||||||
// then its app to the front, showing a hidden dropdown terminal.
|
// then its app to the front, showing a hidden dropdown terminal.
|
||||||
func Raise(front string) {
|
func Raise(front string) {
|
||||||
c, app, reach := place(front)
|
c, app, reach := place(front)
|
||||||
if reach == 0 {
|
if reach == unreachable {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if inTmux() {
|
if inTmux() {
|
||||||
pane := os.Getenv("TMUX_PANE")
|
pane := os.Getenv("TMUX_PANE")
|
||||||
_, _ = tmux("select-window", "-t", pane)
|
_, _ = tmux("select-window", "-t", pane)
|
||||||
_, _ = tmux("select-pane", "-t", pane)
|
_, _ = tmux("select-pane", "-t", pane)
|
||||||
if reach == 1 {
|
if reach == switchable {
|
||||||
_, _ = tmux("switch-client", "-c", c.name, "-t", pane)
|
_, _ = tmux("switch-client", "-c", c.name, "-t", pane)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ const (
|
|||||||
// DefaultServers are where releases are looked for, in order.
|
// DefaultServers are where releases are looked for, in order.
|
||||||
var DefaultServers = []string{GitHubRepo, DefaultRepo}
|
var DefaultServers = []string{GitHubRepo, DefaultRepo}
|
||||||
|
|
||||||
// latestTimeout bounds asking one server for the latest release, so a
|
// serverTimeout bounds asking one server for the latest release or its
|
||||||
// server that's down leaves time for the next.
|
// checksums, so a server that's down leaves time for the next.
|
||||||
const latestTimeout = 5 * time.Second
|
const serverTimeout = 5 * time.Second
|
||||||
|
|
||||||
// maxDownload bounds what's read from the server.
|
// maxDownload bounds what's read from the server.
|
||||||
const maxDownload = 200 << 20
|
const maxDownload = 200 << 20
|
||||||
@@ -153,7 +153,7 @@ func (c *Client) latest(ctx context.Context, repo string) (Release, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return Release{}, err
|
return Release{}, err
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithTimeout(ctx, latestTimeout)
|
ctx, cancel := context.WithTimeout(ctx, serverTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
// The recent releases in one request (per_page on GitHub, limit on
|
// The recent releases in one request (per_page on GitHub, limit on
|
||||||
// Gitea), for their changelogs.
|
// Gitea), for their changelogs.
|
||||||
@@ -222,7 +222,7 @@ func (c *Client) Install(ctx context.Context, r Release, exe string) error {
|
|||||||
if m := Managed(exe); m != "" {
|
if m := Managed(exe); m != "" {
|
||||||
return fmt.Errorf("%s is managed by %s: update it there", exe, m)
|
return fmt.Errorf("%s is managed by %s: update it there", exe, m)
|
||||||
}
|
}
|
||||||
if runtime.GOOS != "darwin" && runtime.GOOS != "linux" || runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64" {
|
if (runtime.GOOS != "darwin" && runtime.GOOS != "linux") || (runtime.GOARCH != "amd64" && runtime.GOARCH != "arm64") {
|
||||||
return fmt.Errorf("no release build for %s/%s", runtime.GOOS, runtime.GOARCH)
|
return fmt.Errorf("no release build for %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
version := strings.TrimPrefix(r.Tag, "v")
|
version := strings.TrimPrefix(r.Tag, "v")
|
||||||
@@ -272,7 +272,7 @@ func (c *Client) download(ctx context.Context, tag, file string) ([]byte, error)
|
|||||||
var errs []error
|
var errs []error
|
||||||
for _, repo := range c.servers() {
|
for _, repo := range c.servers() {
|
||||||
base := strings.TrimSuffix(repo, "/") + "/releases/download/" + tag + "/"
|
base := strings.TrimSuffix(repo, "/") + "/releases/download/" + tag + "/"
|
||||||
sctx, cancel := context.WithTimeout(ctx, latestTimeout)
|
sctx, cancel := context.WithTimeout(ctx, serverTimeout)
|
||||||
sums, err := c.get(sctx, base+"checksums.txt", 1<<20)
|
sums, err := c.get(sctx, base+"checksums.txt", 1<<20)
|
||||||
cancel()
|
cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in new issue
Block a user