1package main
2
3import (
4 "github.com/gdamore/tcell/v2"
5 "log"
6 "os"
7)
8
9func initScreen() (tcell.Screen, error) {
10 s, err := tcell.NewScreen()
11 if err != nil {
12 return nil, err
13 }
14 if err := s.Init(); err != nil {
15 return nil, err
16 }
17 s.SetStyle(defStyle)
18 s.EnablePaste()
19 s.Clear()
20 return s, nil
21}
22
23func fatal(ui *UserInterface, v ...any) {
24 cleanup(ui)
25 log.Fatal(v...)
26}
27
28func handleEventKey(ui *UserInterface, ev *tcell.EventKey) {
29 switch ev.Key() {
30 case tcell.KeyEnter:
31 err := ui.withoutScreen(func() error {
32 mail := ui.SelectedMail()
33 return mail.Show()
34 })
35 if err != nil {
36 fatal(ui, err)
37 }
38 case tcell.KeyRune:
39 mail := ui.SelectedMail()
40 switch ev.Rune() {
41 case 'r':
42 err := ui.withoutScreen(func() error {
43 mail := ui.SelectedMail()
44 return mail.Reply()
45 })
46 if err != nil {
47 fatal(ui, err)
48 }
49 case 'd':
50 err := os.Remove(mail.Path)
51 if err != nil {
52 fatal(ui, err)
53 }
54 case 'f':
55 mail.Flag(Flagged)
56 case 'F':
57 mail.Flag(Unflagged)
58 case 's':
59 mail.Flag(Unseen)
60 case 'S':
61 mail.Flag(Seen)
62 case 't':
63 mail.Flag(Untrashed)
64 case 'T':
65 mail.Flag(Trashed)
66 default:
67 return
68 }
69
70 // TODO: Consider using `mflag -v` above to determine the
71 // new file names and thereby keep the sequence in tact.
72
73 err := ui.Refresh()
74 if err != nil {
75 fatal(ui, err)
76 }
77
78 ui.Screen.Clear()
79 ui.Draw()
80 case tcell.KeyDown:
81 ui.NextMail()
82 case tcell.KeyUp:
83 ui.PrevMail()
84 case tcell.KeyPgDn:
85 ui.NextPage()
86 case tcell.KeyPgUp:
87 ui.PrevPage()
88 case tcell.KeyCtrlL:
89 ui.Screen.Sync()
90 }
91}
92
93func eventLoop(ui *UserInterface) {
94 for {
95 ui.Screen.Show()
96 ev := ui.Screen.PollEvent()
97
98 switch ev := ev.(type) {
99 case *tcell.EventResize:
100 ui.Draw()
101 ui.Screen.Sync()
102 case *tcell.EventKey:
103 if ev.Key() == tcell.KeyEscape ||
104 ev.Key() == tcell.KeyCtrlC ||
105 (ev.Key() == tcell.KeyRune && ev.Rune() == 'q') {
106 return
107 }
108
109 handleEventKey(ui, ev)
110 }
111 }
112}
113
114func cleanup(ui *UserInterface) {
115 // You have to catch panics in a defer, clean up, and
116 // re-raise them - otherwise your application can
117 // die without leaving any diagnostic trace.
118 maybePanic := recover()
119
120 ui.Screen.Fini()
121 if maybePanic != nil {
122 panic(maybePanic)
123 }
124}
125
126func main() {
127 mails, err := mscan()
128 if err != nil {
129 log.Fatal(err)
130 }
131
132 screen, err := initScreen()
133 if err != nil {
134 log.Fatal(err)
135 }
136
137 ui := NewUI(mails, screen)
138 defer cleanup(ui)
139
140 ui.Draw()
141 eventLoop(ui)
142}