Cleanup pane, Pi session tools, review from the UI, project registry, needs panel acts

This commit is contained in:
Sam
2026-11-11 14:16:12 +11:00
parent 0476afcb95
commit 3ec960e349
16 changed files with 726 additions and 18 deletions

View File

@@ -9,6 +9,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
@@ -55,7 +56,7 @@ type projectModel struct {
width, height int
}
var projectTabs = []string{"overview", "facts", "costs", "settings"}
var projectTabs = []string{"overview", "facts", "costs", "settings", "projects"}
func newProjectModel(c *paperclip.Client, folder string) projectModel {
return projectModel{client: c, folder: folder}
@@ -162,13 +163,13 @@ func (m projectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
return m, tea.Quit
case "[", "h":
case "(", "[", "h":
if m.tab > 0 {
m.tab--
m.scroll = 0
}
return m, nil
case "]", "l", "tab":
case ")", "]", "l", "tab":
if m.tab < len(projectTabs)-1 {
m.tab++
m.scroll = 0
@@ -234,6 +235,8 @@ func (m projectModel) View() string {
body = m.factLines()
case 2:
body = m.costLines()
case 4:
body = m.projectListLines(m.width - 4)
default:
body = m.settingLines()
}
@@ -254,7 +257,7 @@ func (m projectModel) View() string {
to := min(len(body), from+visible)
footer := hintLine([]string{
keyHint("[ ]", "tab"),
keyHint("( )", "tab"),
keyHint("↑↓", "scroll"),
keyHint("r", "refresh"),
keyHint("R", "rebuild"),
@@ -433,3 +436,70 @@ func (m projectModel) verifyCommand() string {
}
var _ = exec.Command
// registryRow is one adopted project, from the file bin/office writes.
type registryRow struct {
name, folder, host, session, id string
}
// readRegistry lists adopted projects. It is the only thing this program keeps
// besides the project file: where a folder is, and on which machine.
func readRegistry() []registryRow {
home, _ := os.UserHomeDir()
path := filepath.Join(home, ".config", "paperclip-harness", "projects.toml")
b, err := os.ReadFile(path)
if err != nil {
return nil
}
var rows []registryRow
cur := map[string]string{}
id := ""
flush := func() {
if id != "" && cur["folder"] != "" {
rows = append(rows, registryRow{
name: cur["name"], folder: cur["folder"], host: cur["host"],
session: cur["session"], id: id,
})
}
cur = map[string]string{}
}
for _, line := range strings.Split(string(b), "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "[projects.") {
flush()
id = strings.Trim(strings.TrimPrefix(line, "[projects."), "]'\"")
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
cur[strings.TrimSpace(parts[0])] = strings.Trim(strings.TrimSpace(parts[1]), "\"'")
}
flush()
return rows
}
// projectListLines shows every adopted project and where it lives.
func (m projectModel) projectListLines(width int) []string {
rows := readRegistry()
out := []string{"", dimStyle().Render(fmt.Sprintf(" %-26s %-12s %-14s %s", "project", "machine", "session", "folder"))}
me, _ := os.Hostname()
for _, r := range rows {
here := ""
if r.host == me || r.host == strings.Split(me, ".")[0] {
here = " (this machine)"
}
line := fmt.Sprintf(" %-26s %-12s %-14s %s%s",
truncateVisible(r.name, 26), r.host, truncateVisible(r.session, 14),
truncateVisible(r.folder, max(10, width-60)), here)
out = append(out, line)
}
if len(rows) == 0 {
out = append(out, " "+mutedStyle2().Render("none adopted yet: bin/office <folder> adds one"))
}
out = append(out, "")
out = append(out, dimStyle().Render(" a project on another machine can be listed here but not opened from this one."))
out = append(out, dimStyle().Render(" to open one: attach to its session, or run bin/office <folder> there."))
return out
}