[Help with the code 🙇] : I need to cancel progress bar twice to get back to terminal. #1124
-
My Question
First
|
Beta Was this translation helpful? Give feedback.
Answered by
akash-aman
Aug 30, 2024
Replies: 1 comment
-
Got the issue, I messed up with context channel, forgot to check some blocking conditions. correct codepackage main
import (
"context"
"os"
"os/signal"
"reflect"
"strings"
"sync"
"syscall"
"time"
"github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
const (
padding = 2
maxWidth = 80
)
var (
helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#626262")).Render
)
type (
Progress struct {
progressModel progress.Model
percentChan chan float64
isComplete float64
context context.Context
cancel context.CancelFunc
}
tickMsg time.Time
)
func NewProgress(ctx context.Context, can context.CancelFunc) *Progress {
return &Progress{
progressModel: progress.New(progress.WithDefaultGradient()),
percentChan: make(chan float64, 1),
isComplete: 1.0,
context: ctx,
cancel: can,
}
}
func (m *Progress) Run(wg *sync.WaitGroup) {
defer m.cancel()
defer wg.Done()
tea.NewProgram(m, tea.WithContext(m.context)).Run()
}
func (m *Progress) Init() tea.Cmd {
return tea.Batch(tea.ClearScreen, tickCmd())
}
func (m *Progress) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
return m, tea.Batch(tea.ClearScreen,tea.Quit)
case tea.WindowSizeMsg:
m.progressModel.Width = msg.Width - padding*2 - 4
if m.progressModel.Width > maxWidth {
m.progressModel.Width = maxWidth
}
return m, nil
case progress.FrameMsg:
progressModel, cmd := m.progressModel.Update(msg)
m.progressModel = progressModel.(progress.Model)
return m, cmd
case tickMsg:
if m.progressModel.Percent() >= m.isComplete {
return m, tea.Tick(time.Millisecond, tickCallback(tea.Quit))
}
select {
case percent := <-m.percentChan:
return m, tea.Batch(tickCmd(), m.progressModel.IncrPercent(percent))
default:
return m, tickCmd()
}
default:
return m, nil
}
}
func (m *Progress) View() string {
pad := strings.Repeat(" ", padding)
if m.progressModel.Percent() >= m.isComplete {
return ""
}
return pad + m.progressModel.View() + "\n\n" +
pad + helpStyle("Press any key to quit")
}
func (p *Progress) UpdateProgress(percent float64) {
select {
case <-p.context.Done():
default:
select {
case p.percentChan <- percent:
default:
return
}
}
}
func tickCallback(t tea.Msg) func(time.Time) tea.Msg {
return func(time time.Time) tea.Msg {
tType := reflect.TypeOf(t)
if tType.Kind() == reflect.Func {
results := reflect.ValueOf(t).Call(nil)
if len(results) > 0 {
return results[0].Interface()
}
return nil
}
return t
}
}
func tickCmd() tea.Cmd {
return tea.Tick(time.Millisecond*500, func(t time.Time) tea.Msg {
return tickMsg(t)
})
}
func main() {
var wg sync.WaitGroup
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
defer wg.Wait()
p := NewProgress(ctx, cancel)
wg.Add(1)
go p.Run(&wg)
for i := 0; i <= 10; i++ {
select {
case <-ctx.Done():
return
default:
p.UpdateProgress(0.2)
time.Sleep(1 * time.Second)
}
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
akash-aman
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Got the issue, I messed up with context channel, forgot to check some blocking conditions.
correct code