init: pristine aerc 0.20.0 source
This commit is contained in:
+243
@@ -0,0 +1,243 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"git.sr.ht/~rjarry/aerc/config"
|
||||
"git.sr.ht/~rjarry/aerc/lib/log"
|
||||
"git.sr.ht/~rjarry/aerc/lib/ui"
|
||||
"git.sr.ht/~rockorager/vaxis"
|
||||
"github.com/riywo/loginshell"
|
||||
)
|
||||
|
||||
var qt quakeTerminal
|
||||
|
||||
type quakeTerminal struct {
|
||||
mu sync.Mutex
|
||||
rolling int32
|
||||
visible bool
|
||||
term *Terminal
|
||||
}
|
||||
|
||||
func ToggleQuake() {
|
||||
handleErr := func(err error) {
|
||||
log.Errorf("quake-terminal: %v", err)
|
||||
}
|
||||
if !qt.HasTerm() {
|
||||
shell, err := loginshell.Shell()
|
||||
if err != nil {
|
||||
handleErr(err)
|
||||
return
|
||||
}
|
||||
args := []string{shell}
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
term, err := NewTerminal(cmd)
|
||||
if err != nil {
|
||||
handleErr(err)
|
||||
return
|
||||
}
|
||||
term.OnClose = func(err error) {
|
||||
if err != nil {
|
||||
aerc.PushError(err.Error())
|
||||
}
|
||||
qt.Hide()
|
||||
qt.SetTerm(nil)
|
||||
}
|
||||
qt.SetTerm(term)
|
||||
}
|
||||
|
||||
if qt.Rolling() {
|
||||
return
|
||||
}
|
||||
|
||||
if qt.Visible() {
|
||||
qt.Hide()
|
||||
} else {
|
||||
qt.Show()
|
||||
}
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) Rolling() bool {
|
||||
return atomic.LoadInt32(&q.rolling) > 0
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) SetTerm(t *Terminal) {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
q.term = t
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) HasTerm() bool {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
return q.term != nil
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) Visible() bool {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
return q.visible
|
||||
}
|
||||
|
||||
// inputReturn is helper function to create dialog boxes.
|
||||
func inputReturn() func(int) int {
|
||||
return func(x int) int { return x }
|
||||
}
|
||||
|
||||
// fixReturn is helper function to create dialog boxes.
|
||||
func fixReturn(x int) func(int) int {
|
||||
return func(_ int) int { return x }
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) Show() {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
if q.term == nil {
|
||||
return
|
||||
}
|
||||
|
||||
uiConfig := SelectedAccountUiConfig()
|
||||
h := uiConfig.QuakeHeight
|
||||
|
||||
termBox := NewDialog(
|
||||
ui.NewBox(q.term, "", "", uiConfig),
|
||||
fixReturn(0),
|
||||
fixReturn(0),
|
||||
inputReturn(),
|
||||
fixReturn(h),
|
||||
)
|
||||
|
||||
f := Roller{
|
||||
span: 100 * time.Millisecond,
|
||||
done: func() {
|
||||
log.Tracef("restore after show")
|
||||
atomic.StoreInt32(&q.rolling, 0)
|
||||
ui.QueueFunc(func() {
|
||||
CloseDialog()
|
||||
AddDialog(termBox)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
atomic.StoreInt32(&q.rolling, 1)
|
||||
emptyBox := NewDialog(
|
||||
ui.NewBox(&EmptyInteractive{}, "", "", uiConfig),
|
||||
fixReturn(0),
|
||||
fixReturn(0),
|
||||
inputReturn(),
|
||||
f.Roll(1, h),
|
||||
)
|
||||
|
||||
q.visible = true
|
||||
if q.term != nil {
|
||||
q.term.Show(q.visible)
|
||||
q.term.Focus(q.visible)
|
||||
}
|
||||
|
||||
CloseDialog()
|
||||
AddDialog(emptyBox)
|
||||
}
|
||||
|
||||
func (q *quakeTerminal) Hide() {
|
||||
uiConfig := SelectedAccountUiConfig()
|
||||
f := Roller{
|
||||
span: 100 * time.Millisecond,
|
||||
done: func() {
|
||||
atomic.StoreInt32(&q.rolling, 0)
|
||||
ui.QueueFunc(CloseDialog)
|
||||
log.Tracef("restore after hide")
|
||||
},
|
||||
}
|
||||
|
||||
atomic.StoreInt32(&q.rolling, 1)
|
||||
emptyBox := NewDialog(
|
||||
ui.NewBox(&EmptyInteractive{}, "", "", uiConfig),
|
||||
fixReturn(0),
|
||||
fixReturn(0),
|
||||
inputReturn(),
|
||||
f.Roll(uiConfig.QuakeHeight, 2),
|
||||
)
|
||||
|
||||
q.mu.Lock()
|
||||
q.visible = false
|
||||
if q.term != nil {
|
||||
q.term.Focus(q.visible)
|
||||
q.term.Show(q.visible)
|
||||
}
|
||||
q.mu.Unlock()
|
||||
|
||||
ui.QueueFunc(func() {
|
||||
CloseDialog()
|
||||
AddDialog(emptyBox)
|
||||
})
|
||||
}
|
||||
|
||||
type EmptyInteractive struct{}
|
||||
|
||||
func (e *EmptyInteractive) Draw(ctx *ui.Context) {
|
||||
w := ctx.Width()
|
||||
h := ctx.Height()
|
||||
if w == 0 || h == 0 {
|
||||
return
|
||||
}
|
||||
style := SelectedAccountUiConfig().GetStyle(config.STYLE_DEFAULT)
|
||||
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style)
|
||||
}
|
||||
|
||||
func (e *EmptyInteractive) Invalidate() {
|
||||
}
|
||||
|
||||
func (e *EmptyInteractive) MouseEvent(_ int, _ int, _ vaxis.Event) {
|
||||
}
|
||||
|
||||
func (e *EmptyInteractive) Event(_ vaxis.Event) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *EmptyInteractive) Focus(_ bool) {
|
||||
}
|
||||
|
||||
type Roller struct {
|
||||
span time.Duration
|
||||
done func()
|
||||
value int64
|
||||
}
|
||||
|
||||
func (f *Roller) Roll(start, end int) func(int) int {
|
||||
nsteps := end - start
|
||||
|
||||
var step int64 = 1
|
||||
if end < start {
|
||||
step = -1
|
||||
nsteps = -nsteps
|
||||
}
|
||||
|
||||
span := f.span.Milliseconds() / int64(nsteps)
|
||||
refresh := time.Duration(span) * time.Millisecond
|
||||
|
||||
atomic.StoreInt64(&f.value, int64(start))
|
||||
|
||||
go func() {
|
||||
defer log.PanicHandler()
|
||||
for i := 0; i < int(nsteps); i++ {
|
||||
aerc.Invalidate()
|
||||
time.Sleep(refresh)
|
||||
atomic.AddInt64(&f.value, step)
|
||||
}
|
||||
if f.done != nil {
|
||||
ui.QueueFunc(f.done)
|
||||
}
|
||||
}()
|
||||
|
||||
return func(_ int) int {
|
||||
log.Tracef("in roller")
|
||||
return int(atomic.LoadInt64(&f.value))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user