mirror of
https://git.sr.ht/~rjarry/aerc
synced 2025-11-06 01:52:02 +01:00
When receiving the SIGHUP signal, reload all configuration. Changelog-added: `:reload` is now invoked when `SIGHUP` is received by the `aerc` process. Suggested-by: Anachron <gith@cron.world> Signed-off-by: Robin Jarry <robin@jarry.cc>
208 lines
3.9 KiB
Go
208 lines
3.9 KiB
Go
package commands
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"git.sr.ht/~rjarry/aerc/app"
|
|
"git.sr.ht/~rjarry/aerc/config"
|
|
"git.sr.ht/~rjarry/aerc/lib/log"
|
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
|
)
|
|
|
|
type Reload struct {
|
|
Binds bool `opt:"-B" desc:"Reload binds.conf."`
|
|
Conf bool `opt:"-C" desc:"Reload aerc.conf."`
|
|
Style string `opt:"-s" complete:"CompleteStyle" desc:"Reload the specified styleset."`
|
|
}
|
|
|
|
func init() {
|
|
Register(Reload{})
|
|
sig := make(chan os.Signal, 1)
|
|
signal.Notify(sig, syscall.SIGHUP)
|
|
go func() {
|
|
defer log.PanicHandler()
|
|
for range sig {
|
|
log.Infof("received SIGHUP, reloading configuration")
|
|
err := Reload{}.Execute(nil)
|
|
if err != nil {
|
|
log.Errorf("reload failed: %s", err)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (Reload) Description() string {
|
|
return "Hot-reload configuration files."
|
|
}
|
|
|
|
func (r *Reload) CompleteStyle(s string) []string {
|
|
var files []string
|
|
for _, dir := range config.Ui().StyleSetDirs {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
log.Debugf("could not read directory '%s': %v", dir,
|
|
err)
|
|
continue
|
|
}
|
|
for _, e := range entries {
|
|
if e.IsDir() {
|
|
continue
|
|
}
|
|
files = append(files, e.Name())
|
|
}
|
|
}
|
|
return FilterList(files, s, nil)
|
|
}
|
|
|
|
func (Reload) Context() CommandContext {
|
|
return GLOBAL
|
|
}
|
|
|
|
func (Reload) Aliases() []string {
|
|
return []string{"reload"}
|
|
}
|
|
|
|
func (r Reload) Execute(args []string) error {
|
|
if !r.Binds && !r.Conf && r.Style == "" {
|
|
r.Binds = true
|
|
r.Conf = true
|
|
r.Style = config.Ui().StyleSetName
|
|
}
|
|
|
|
reconfigure := false
|
|
|
|
if r.Binds {
|
|
f, err := config.ReloadBinds()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
app.PushSuccess("Binds reloaded: " + f)
|
|
}
|
|
|
|
if r.Conf {
|
|
f, err := config.ReloadConf()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
app.PushSuccess("Conf reloaded: " + f)
|
|
reconfigure = true
|
|
}
|
|
|
|
if r.Style != "" {
|
|
config.Ui().ClearCache()
|
|
config.Ui().StyleSetName = r.Style
|
|
err := config.Ui().LoadStyle()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
app.PushSuccess("Styleset: " + r.Style)
|
|
reconfigure = true
|
|
}
|
|
|
|
if !reconfigure {
|
|
return nil
|
|
}
|
|
|
|
// reload account views and message stores
|
|
for _, name := range app.AccountNames() {
|
|
|
|
// rebuild account view
|
|
view, err := app.Account(name)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
dirlist := view.Directories()
|
|
if dirlist == nil {
|
|
continue
|
|
}
|
|
|
|
wantTree := config.Ui().ForAccount(name).DirListTree
|
|
dirlist = adjustDirlist(dirlist, wantTree)
|
|
view.SetDirectories(dirlist)
|
|
|
|
// now rebuild grid with correct dirlist
|
|
view.Configure()
|
|
|
|
// reconfigure the message stores
|
|
for _, dir := range dirlist.List() {
|
|
store, ok := dirlist.MsgStore(dir)
|
|
if !ok {
|
|
continue
|
|
}
|
|
uiConf := dirlist.UiConfig(dir)
|
|
store.Configure(view.SortCriteria(uiConf))
|
|
}
|
|
ui.Invalidate()
|
|
}
|
|
|
|
// reload message viewers
|
|
doTabs(func(tab *ui.Tab) {
|
|
mv, ok := tab.Content.(*app.MessageViewer)
|
|
if !ok {
|
|
return
|
|
}
|
|
reloaded, err := app.NewMessageViewer(
|
|
mv.SelectedAccount(),
|
|
mv.MessageView(),
|
|
)
|
|
if err != nil {
|
|
app.PushError(err.Error())
|
|
return
|
|
}
|
|
app.ReplaceTab(mv, reloaded, tab.Name, false)
|
|
})
|
|
|
|
// reload composers
|
|
doTabs(func(tab *ui.Tab) {
|
|
c, ok := tab.Content.(*app.Composer)
|
|
if !ok {
|
|
return
|
|
}
|
|
_ = c.SwitchAccount(c.Account())
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
func adjustDirlist(d app.DirectoryLister, wantTree bool) app.DirectoryLister {
|
|
switch d := d.(type) {
|
|
case *app.DirectoryList:
|
|
if wantTree {
|
|
log.Tracef("dirlist: build tree")
|
|
tree := app.NewDirectoryTree(d)
|
|
tree.SelectedMsgStore()
|
|
return tree
|
|
}
|
|
log.Tracef("dirlist: already dirlist")
|
|
return d
|
|
case *app.DirectoryTree:
|
|
if !wantTree {
|
|
log.Tracef("dirtree: get dirlist")
|
|
return d.DirectoryList
|
|
}
|
|
log.Tracef("dirtree: already tree")
|
|
return d
|
|
default:
|
|
return d
|
|
}
|
|
}
|
|
|
|
func doTabs(do func(*ui.Tab)) {
|
|
var tabname string
|
|
if t := app.SelectedTab(); t != nil {
|
|
tabname = t.Name
|
|
}
|
|
for i := range app.TabNames() {
|
|
tab := app.GetTab(i)
|
|
if tab == nil {
|
|
continue
|
|
}
|
|
do(tab)
|
|
}
|
|
if tabname != "" {
|
|
app.SelectTab(tabname)
|
|
}
|
|
}
|