Skip to content

Commit

Permalink
cf: allow changing folder of another account
Browse files Browse the repository at this point in the history
Add a new -a flag to :cf. When specified, an account name is required
before the folder name and the focus will be changed to the
corresponding account tab before changing folders.

If the target folder does not exist, an explicit error will be reported.

Changelog-added: Change to a folder of another account with
 `:cf -a <account> <folder>`.
Signed-off-by: Robin Jarry <[email protected]>
Co-authored-by: Johannes Thyssen Tishman <[email protected]>
Tested-by: Johannes Thyssen Tishman <[email protected]>
  • Loading branch information
rjarry and thyssentishman committed Dec 5, 2023
1 parent c67723b commit 2db657b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 25 deletions.
8 changes: 8 additions & 0 deletions app/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ func (acct *AccountView) UpdateStatus() {
}
}

func (acct *AccountView) Select() {
for i, widget := range aerc.tabs.TabContent.Children() {
if widget == acct {
aerc.SelectTabIndex(i)
}
}
}

func (acct *AccountView) PushStatus(status string, expiry time.Duration) {
PushStatus(fmt.Sprintf("%s: %s", acct.acct.Name, status), expiry)
}
Expand Down
89 changes: 66 additions & 23 deletions commands/account/cf.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package account
import (
"errors"
"reflect"
"time"

"git.sr.ht/~rjarry/aerc/app"
"git.sr.ht/~rjarry/aerc/commands"
Expand All @@ -16,7 +17,8 @@ import (
var history map[string]string

type ChangeFolder struct {
Folder string `opt:"..." complete:"CompleteFolder"`
Account bool `opt:"-a"`
Folder string `opt:"..." complete:"CompleteFolder"`
}

func init() {
Expand All @@ -28,8 +30,20 @@ func (ChangeFolder) Aliases() []string {
return []string{"cf"}
}

func (*ChangeFolder) CompleteFolder(arg string) []string {
acct := app.SelectedAccount()
func (c *ChangeFolder) CompleteFolder(arg string) []string {
var acct *app.AccountView

args := opt.LexArgs(c.Folder)
if c.Account {
accountName, _ := args.ArgSafe(0)
if args.Count() <= 1 && arg == accountName {
return commands.FilterList(
app.AccountNames(), arg, commands.QuoteSpace)
}
acct, _ = app.Account(accountName)
} else {
acct = app.SelectedAccount()
}
if acct == nil {
return nil
}
Expand All @@ -45,46 +59,75 @@ func (*ChangeFolder) CompleteFolder(arg string) []string {
)
}

func (c ChangeFolder) Execute(args []string) error {
acct := app.SelectedAccount()
if acct == nil {
return errors.New("No account selected")
func (c ChangeFolder) Execute([]string) error {
var target string
var acct *app.AccountView

args := opt.LexArgs(c.Folder)

if c.Account {
names, err := args.ShiftSafe(1)
if err != nil {
return errors.New("<account> is required. Usage: cf -a <account> <folder>")
}
acct, err = app.Account(names[0])
if err != nil {
return err
}
} else {
acct = app.SelectedAccount()
if acct == nil {
return errors.New("No account selected")
}
}

var target string
if args.Count() == 0 {
return errors.New("<folder> is required. Usage: cf [-a <account>] <folder>")
}

notmuch, _ := handlers.GetHandlerForScheme("notmuch", new(types.Worker))
if reflect.TypeOf(notmuch) == reflect.TypeOf(acct.Worker().Backend) {
// With notmuch, :cf can change to a "dynamic folder" that
// contains the result of a query. Preserve the entered
// arguments verbatim.
target = c.Folder
target = args.String()
} else {
parts := opt.SplitArgs(c.Folder)
if len(parts) != 1 {
return errors.New("Unexpected argument(s). Usage: cf <folder>")
if args.Count() != 1 {
return errors.New("Unexpected argument(s). Usage: cf [-a <account>] <folder>")
}
target = parts[0]
target = args.Arg(0)
}

previous := acct.Directories().Selected()
finalize := func(msg types.WorkerMessage) {
// As we're waiting for the worker to report status we must run
// the rest of the actions in this callback.
switch msg := msg.(type) {
case *types.Error:
app.PushError(msg.Error.Error())
case *types.Done:
curAccount := app.SelectedAccount()
previous := curAccount.Directories().Selected()
history[curAccount.Name()] = previous
// reset store filtering if we switched folders
store := acct.Store()
if store != nil {
store.ApplyClear()
acct.SetStatus(state.SearchFilterClear())
}
// focus account tab
acct.Select()
}
}

if target == "-" {
if dir, ok := history[acct.Name()]; ok {
acct.Directories().Select(dir)
acct.Directories().Open(dir, 0*time.Second, finalize)
} else {
return errors.New("No previous folder to return to")
}
} else {
acct.Directories().Select(target)
acct.Directories().Open(target, 0*time.Second, finalize)
}
history[acct.Name()] = previous

// reset store filtering if we switched folders
store := acct.Store()
if store != nil {
store.ApplyClear()
acct.SetStatus(state.SearchFilterClear())
}
return nil
}
8 changes: 6 additions & 2 deletions doc/aerc.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,12 @@ message list, the message in the message viewer, etc).

*-s*: Selects the message at the top of the message list after clearing.

*:cf* _<folder>_
Change the folder shown in the message list.
*:cf* [*-a* _<account>_] _<folder>_
Change the folder shown in the message list to _<folder>_.

*-a* _<account>_
Change to _<folder>_ of _<account>_ and focus its corresponding
tab.

*:check-mail*
Check for new mail on the selected account. Non-imap backends require
Expand Down

0 comments on commit 2db657b

Please sign in to comment.