feat: long names in questions cut with … and the window as wide as its words; SSH dialog hides «Вход» for a saved host and says «подключение…» quietly; zip and unzip on SSH hosts without them through Python's zipfile

This commit is contained in:
redtea committed 2026-10-16 09:31:21 +03:00
1 parent 6db78399ac
commit 434900a168
5 files changed
+40 -20

No files matched your search

+9 -4
View File
@@ -139,7 +139,8 @@ func (a *Agent) sshfsOpen(ctx context.Context, t proto.SSHTarget) (any, error) {
}
c := &sshfsConn{client: client, target: t, last: time.Now()}
out, _ := sshRun(client, "stat -c %F / >/dev/null 2>&1 && echo GNU; stat -f %HT / >/dev/null 2>&1 && echo BSD; "+
"command -v zip >/dev/null 2>&1 && echo ZIP; command -v unzip >/dev/null 2>&1 && echo UNZIP; echo \"$HOME\"")
"command -v zip >/dev/null 2>&1 && echo ZIP; command -v unzip >/dev/null 2>&1 && echo UNZIP; "+
"command -v python3 >/dev/null 2>&1 && echo PY; echo \"$HOME\"")
lines := strings.Split(strings.TrimSpace(out), "\n")
switch {
case strings.Contains(out, "GNU"):
@@ -158,7 +159,7 @@ func (a *Agent) sshfsOpen(ctx context.Context, t proto.SSHTarget) (any, error) {
sshfsJanitor.Do(func() { go sshfsSweep() })
// zip and unzip, where the host has them, for the pane's buttons.
return map[string]any{"id": id, "home": c.home,
"zip": hasLine(lines, "ZIP"), "unzip": hasLine(lines, "UNZIP")}, nil
"zip": hasLine(lines, "ZIP") || hasLine(lines, "PY"), "unzip": hasLine(lines, "UNZIP") || hasLine(lines, "PY")}, nil
}
func hasLine(lines []string, w string) bool {
@@ -410,7 +411,10 @@ func zipCommand(paths []string, dest string) (string, error) {
}
names[i] = shq("./" + path.Base(p))
}
return "cd -- " + shq(dir) + " && zip -r -q -y " + shq(path.Clean(dest)) + " " + strings.Join(names, " "), nil
// zip where the host has it, else Python's zipfile, which most have.
items := strings.Join(names, " ")
return "cd -- " + shq(dir) + " && if command -v zip >/dev/null 2>&1; then zip -r -q -y " + shq(path.Clean(dest)) + " " + items + "; " +
"else python3 -m zipfile -c " + shq(path.Clean(dest)) + " " + items + "; fi", nil
}
// unzipCommand unpacks the archive p into dest (its own folder if empty),
@@ -419,7 +423,8 @@ func unzipCommand(p, dest string) string {
if dest == "" {
dest = path.Dir(path.Clean(p))
}
return "unzip -o -q " + shq(path.Clean(p)) + " -d " + shq(path.Clean(dest))
return "if command -v unzip >/dev/null 2>&1; then unzip -o -q " + shq(path.Clean(p)) + " -d " + shq(path.Clean(dest)) + "; " +
"else python3 -m zipfile -e " + shq(path.Clean(p)) + " " + shq(path.Clean(dest)) + "; fi"
}
// writeCommand writes stdin to p through a file beside it, so a broken
+3 -2
View File
@@ -114,7 +114,8 @@ func TestZipCommand(t *testing.T) {
if err != nil {
t.Fatal(err)
}
want := `cd -- '/srv' && zip -r -q -y '/tmp/x.zip' './a b' './it'\''s'`
want := `cd -- '/srv' && if command -v zip >/dev/null 2>&1; then zip -r -q -y '/tmp/x.zip' './a b' './it'\''s'; ` +
`else python3 -m zipfile -c '/tmp/x.zip' './a b' './it'\''s'; fi`
if cmd != want {
t.Fatalf("got %s\nwant %s", cmd, want)
}
@@ -124,7 +125,7 @@ func TestZipCommand(t *testing.T) {
if _, err := zipCommand(nil, "/t.zip"); err == nil {
t.Fatal("no items: want an error")
}
if got := unzipCommand("/srv/a.zip", ""); got != `unzip -o -q '/srv/a.zip' -d '/srv'` {
if got := unzipCommand("/srv/a.zip", ""); got != `if command -v unzip >/dev/null 2>&1; then unzip -o -q '/srv/a.zip' -d '/srv'; else python3 -m zipfile -e '/srv/a.zip' '/srv'; fi` {
t.Fatalf("unzip: %s", got)
}
}