aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/aerc.go10
-rw-r--r--app/compose.go8
-rw-r--r--app/msgviewer.go7
-rw-r--r--commands/patch/list.go113
-rw-r--r--config/cmds.go22
-rw-r--r--lib/pama/list.go59
6 files changed, 202 insertions, 17 deletions
diff --git a/app/aerc.go b/app/aerc.go
index 046c7871..c7307540 100644
--- a/app/aerc.go
+++ b/app/aerc.go
@@ -873,9 +873,9 @@ func (aerc *Aerc) isExKey(event *tcell.EventKey, exKey config.KeyStroke) bool {
return event.Modifiers() == exKey.Modifiers && event.Key() == exKey.Key
}
-// cmdFallbackSearch checks cmds for the first executable availabe in PATH. An error is
+// CmdFallbackSearch checks cmds for the first executable availabe in PATH. An error is
// returned if none are found
-func cmdFallbackSearch(cmds []string) (string, error) {
+func CmdFallbackSearch(cmds []string, silent bool) (string, error) {
var tried []string
for _, cmd := range cmds {
if cmd == "" {
@@ -885,8 +885,10 @@ func cmdFallbackSearch(cmds []string) (string, error) {
_, err := exec.LookPath(params[0])
if err != nil {
tried = append(tried, cmd)
- warn := fmt.Sprintf("cmd '%s' not found in PATH, using fallback", cmd)
- PushWarning(warn)
+ if !silent {
+ warn := fmt.Sprintf("cmd '%s' not found in PATH, using fallback", cmd)
+ PushWarning(warn)
+ }
continue
}
return cmd, nil
diff --git a/app/compose.go b/app/compose.go
index 75f90f12..35fdd9bf 100644
--- a/app/compose.go
+++ b/app/compose.go
@@ -1320,13 +1320,7 @@ func (c *Composer) showTerminal() error {
if c.editor != nil {
c.editor.Destroy()
}
- cmds := []string{
- config.Compose.Editor,
- os.Getenv("EDITOR"),
- "vi",
- "nano",
- }
- editorName, err := cmdFallbackSearch(cmds)
+ editorName, err := CmdFallbackSearch(config.EditorCmds(), false)
if err != nil {
c.acct.PushError(fmt.Errorf("could not start editor: %w", err))
}
diff --git a/app/msgviewer.go b/app/msgviewer.go
index abed93fd..e45a6d3e 100644
--- a/app/msgviewer.go
+++ b/app/msgviewer.go
@@ -421,12 +421,7 @@ func NewPartViewer(
pagerin io.WriteCloser
term *Terminal
)
- cmds := []string{
- config.Viewer.Pager,
- os.Getenv("PAGER"),
- "less -Rc",
- }
- pagerCmd, err := cmdFallbackSearch(cmds)
+ pagerCmd, err := CmdFallbackSearch(config.PagerCmds(), false)
if err != nil {
acct.PushError(fmt.Errorf("could not start pager: %w", err))
return nil, err
diff --git a/commands/patch/list.go b/commands/patch/list.go
new file mode 100644
index 00000000..6dcc06e8
--- /dev/null
+++ b/commands/patch/list.go
@@ -0,0 +1,113 @@
+package patch
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os/exec"
+ "time"
+
+ "git.sr.ht/~rjarry/aerc/app"
+ "git.sr.ht/~rjarry/aerc/config"
+ "git.sr.ht/~rjarry/aerc/lib/pama"
+ "git.sr.ht/~rjarry/aerc/lib/pama/models"
+ "git.sr.ht/~rjarry/aerc/lib/ui"
+ "git.sr.ht/~rjarry/go-opt"
+ "github.com/gdamore/tcell/v2"
+)
+
+type List struct {
+ All bool `opt:"-a"`
+}
+
+func init() {
+ register(List{})
+}
+
+func (List) Aliases() []string {
+ return []string{"list", "ls"}
+}
+
+func (l List) Execute(args []string) error {
+ m := pama.New()
+ current, err := m.CurrentProject()
+ if err != nil {
+ return err
+ }
+
+ projects := []models.Project{current}
+ if l.All {
+ projects, err = m.Projects("")
+ if err != nil {
+ return err
+ }
+ }
+
+ app.PushStatus(fmt.Sprintf("Current project: %s", current.Name), 30*time.Second)
+
+ createWidget := func(r io.Reader) (ui.DrawableInteractive, error) {
+ pagerCmd, err := app.CmdFallbackSearch(config.PagerCmds(), true)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := opt.SplitArgs(pagerCmd)
+ pager := exec.Command(cmd[0], cmd[1:]...)
+ pager.Stdin = r
+
+ term, err := app.NewTerminal(pager)
+ if err != nil {
+ return nil, err
+ }
+ start := time.Now()
+ term.OnClose = func(err error) {
+ if time.Since(start) > 250*time.Millisecond {
+ app.CloseDialog()
+ return
+ }
+ term.OnEvent = func(_ tcell.Event) bool {
+ app.CloseDialog()
+ return true
+ }
+ }
+ return term, nil
+ }
+
+ viewer, err := createWidget(m.NewReader(projects))
+ if err != nil {
+ viewer = app.NewListBox(
+ "Press <Esc> or <Enter> to close. "+
+ "Start typing to filter.",
+ numerify(m.NewReader(projects)), app.SelectedAccountUiConfig(),
+ func(_ string) { app.CloseDialog() },
+ )
+ }
+
+ app.AddDialog(app.NewDialog(
+ ui.NewBox(viewer, "Patch Management", "",
+ app.SelectedAccountUiConfig(),
+ ),
+ // start pos on screen
+ func(h int) int {
+ return h / 8
+ },
+ // dialog height
+ func(h int) int {
+ return h - 2*h/8
+ },
+ ))
+
+ return nil
+}
+
+func numerify(r io.Reader) []string {
+ var lines []string
+ nr := 1
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ s := scanner.Text()
+ lines = append(lines, fmt.Sprintf("%3d %s", nr, s))
+ nr++
+ }
+ return lines
+}
diff --git a/config/cmds.go b/config/cmds.go
new file mode 100644
index 00000000..16208914
--- /dev/null
+++ b/config/cmds.go
@@ -0,0 +1,22 @@
+package config
+
+import (
+ "os"
+)
+
+func EditorCmds() []string {
+ return []string{
+ Compose.Editor,
+ os.Getenv("EDITOR"),
+ "vi",
+ "nano",
+ }
+}
+
+func PagerCmds() []string {
+ return []string{
+ Viewer.Pager,
+ os.Getenv("PAGER"),
+ "less -Rc",
+ }
+}
diff --git a/lib/pama/list.go b/lib/pama/list.go
new file mode 100644
index 00000000..950f130d
--- /dev/null
+++ b/lib/pama/list.go
@@ -0,0 +1,59 @@
+package pama
+
+import (
+ "errors"
+ "io"
+ "strings"
+
+ "git.sr.ht/~rjarry/aerc/lib/pama/models"
+ "git.sr.ht/~rjarry/aerc/log"
+)
+
+func (m PatchManager) Projects(name string) ([]models.Project, error) {
+ all, err := m.store().Projects()
+ if err != nil {
+ return nil, storeErr(err)
+ }
+ if len(name) == 0 {
+ return all, nil
+ }
+ var projects []models.Project
+ for _, p := range all {
+ if strings.Contains(p.Name, name) {
+ projects = append(projects, p)
+ }
+ }
+ if len(projects) == 0 {
+ return nil, errors.New("No projects found.")
+ }
+ return projects, nil
+}
+
+func (m PatchManager) NewReader(projects []models.Project) io.Reader {
+ cur, err := m.CurrentProject()
+ currentName := cur.Name
+ if err != nil {
+ log.Warnf("could not get current project: %v", err)
+ currentName = ""
+ }
+
+ readers := make([]io.Reader, 0, len(projects))
+ for _, p := range projects {
+ rc, err := m.rc(p.RevctrlID, p.Root)
+ if err != nil {
+ log.Errorf("project '%s' failed with: %v", p.Name, err)
+ continue
+ }
+
+ notes := make(map[string]string)
+ for _, c := range p.Commits {
+ if !rc.Exists(c.ID) {
+ notes[c.ID] = "Rebase needed"
+ }
+ }
+
+ active := p.Name == currentName && len(projects) > 1
+ readers = append(readers, p.NewReader(active, notes))
+ }
+ return io.MultiReader(readers...)
+}