From f68970ea6ff687455b3ac842f0af5961ddf234ed Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 28 Apr 2022 22:06:54 +0200 Subject: [PATCH] Better display --- go.mod | 1 + go.sum | 1 + main.go | 109 ++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 84 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index ebedb15..b50fa1c 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/sahilm/fuzzy v0.1.0 // indirect golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/term v0.0.0-20210422114643-f5beecf764ed // indirect diff --git a/go.sum b/go.sum index 1a5db0a..5252c4e 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= diff --git a/main.go b/main.go index fc36452..503dcf6 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,9 @@ import ( "fmt" "github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/textinput" + "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/wish" bm "github.com/charmbracelet/wish/bubbletea" lm "github.com/charmbracelet/wish/logging" @@ -20,6 +22,20 @@ import ( "time" ) +var ( + titleStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Right = "├" + return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1) + }() + + infoStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Left = "┤" + return titleStyle.Copy().BorderStyle(b) + }() +) + func main() { log.Println("Welcome on Cemantics!") @@ -67,7 +83,6 @@ func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) { ti.Focus() ti.CharLimit = 26 ti.Width = 26 - m := model{ textInput: ti, err: nil, @@ -75,7 +90,7 @@ func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) { words: []word{}, progressBar: progress.New(progress.WithScaledGradient("#FF7CCB", "#FDFF8C")), } - return m, []tea.ProgramOption{tea.WithAltScreen()} + return m, []tea.ProgramOption{tea.WithAltScreen(), tea.WithMouseCellMotion()} } type errMsg error @@ -87,13 +102,15 @@ type word struct { } type model struct { - textInput textinput.Model - err error - ip string - words []word - progressBar progress.Model - maxLength int - lastWord string + ready bool + err error + textInput textinput.Model + ip string + words []word + wordsViewport viewport.Model + progressBar progress.Model + maxLength int + lastWord string } func (m model) Init() tea.Cmd { @@ -102,6 +119,7 @@ func (m model) Init() tea.Cmd { func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd + var cmds []tea.Cmd switch msg := msg.(type) { case tea.KeyMsg: @@ -111,20 +129,35 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyCtrlC, tea.KeyEsc: return m, tea.Quit } + case tea.WindowSizeMsg: + headerHeight := lipgloss.Height(m.headerView()) + footerHeight := lipgloss.Height(m.footerView()) + verticalMarginHeight := headerHeight + footerHeight + + if !m.ready { + m.wordsViewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight) + m.wordsViewport.YPosition = headerHeight + m.ready = true + } else { + m.wordsViewport.Width = msg.Width + m.wordsViewport.Height = msg.Height - verticalMarginHeight + } - // We handle errors just like any other message case errMsg: m.err = msg return m, nil } + m.wordsViewport, cmd = m.wordsViewport.Update(msg) + cmds = append(cmds, cmd) m.textInput, cmd = m.textInput.Update(msg) - return m, cmd + cmds = append(cmds, cmd) + + return m, tea.Batch(cmds...) } func (m model) InputWord() (model, tea.Cmd) { input := m.textInput.Value() - log.Printf("Chosen word: %s", input) m.lastWord = input if len(input) > m.maxLength { @@ -132,7 +165,14 @@ func (m model) InputWord() (model, tea.Cmd) { } // TODO: Get distance and ranking from a file // TODO: Reorder the array - m.words = append(m.words, word{input, 200*rand.Float64() - 100, rand.Intn(1000)}) + w := word{input, 200*rand.Float64() - 100, rand.Intn(1000)} + m.words = append(m.words, w) + + var content string + for _, w := range m.words { + content += w.View(m) + } + m.wordsViewport.SetContent(content) m.textInput.SetValue("") m.textInput.CursorStart() @@ -178,23 +218,38 @@ func (w word) View(m model) string { ) } -func (m model) View() string { +func (m model) headerView() string { + var err string + + if m.err != nil { + err = fmt.Sprintf("Erreur : %s", m.err) + } + msg := fmt.Sprintf( - "Veuillez choisir un mot :\n\n%s\n\n%s", + "Veuillez choisir un mot :\n\n%s\n\nDernier mot essayé : %s%s\n%s\n\n", m.textInput.View(), - "(Esc pour quitter)", - ) + "\n\n" + m.lastWord, + strings.Repeat(" ", 26), + err, + ) - if m.lastWord != "" { - msg += fmt.Sprintf("Dernier mot essayé : %s\n\n", m.lastWord) - } - - if len(m.words) > 0 { - msg += fmt.Sprintf("Liste des derniers mots :\n") - for _, w := range m.words { - msg += w.View(m) - } - } + title := titleStyle.Render("Mots précédents") + line := strings.Repeat("─", int(math.Max(0, float64(m.wordsViewport.Width-lipgloss.Width(title))))) + msg += lipgloss.JoinHorizontal(lipgloss.Center, title, line) return msg } + +func (m model) footerView() string { + info := infoStyle.Render(fmt.Sprintf("%3.f%%", m.wordsViewport.ScrollPercent()*100)) + line := strings.Repeat("─", int(math.Max(0, float64(m.wordsViewport.Width-lipgloss.Width(info))))) + return lipgloss.JoinHorizontal(lipgloss.Center, line, info) +} + +func (m model) View() string { + if !m.ready { + return "\n\tInitializing..." + } + + return fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.wordsViewport.View(), m.footerView()) +}