terminal must be dragged before viewport displays #442
Replies: 12 comments 2 replies
-
Hi! Which terminal emulator are you using? |
Beta Was this translation helpful? Give feedback.
-
Iterm 2 and also default mac terminal |
Beta Was this translation helpful? Give feedback.
-
can you share a full reproducible of the issue? |
Beta Was this translation helpful? Give feedback.
-
I can't reproduce with that due to missing api keys. Could you provide an example program with just the minimum required to reproduce the issue? (i.e. dummy data, just the viewport, etc) |
Beta Was this translation helpful? Give feedback.
-
For a full reproduction package main
import (
"context"
"fmt"
"log"
"strings"
"github.com/PullRequestInc/go-gpt3"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
)
const (
uiMainPage uiState = iota
uiIsLoading
uiLoaded
useHighPerformanceRenderer = false
)
var (
textStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("175")).Bold(true).Render
docStyle = lipgloss.NewStyle().Padding(3).Render
helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render
// border = lipgloss.NewStyle().
// BorderStyle(lipgloss.RoundedBorder()).
// BorderForeground(lipgloss.Color("228")).
// BorderTop(true).
// BorderLeft(true).
// BorderRight(true).BorderBottom(true).Render
color = termenv.EnvColorProfile().Color
MainRuler = lipgloss.NewStyle().
Border(lipgloss.ThickBorder(), true, false).Render
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)
}()
)
type model struct {
textInput textinput.Model
uiState uiState
response string
err error
spinner spinner.Model
isReady bool
quitting bool
viewport viewport.Model
}
type uiState int
func (m model) Init() tea.Cmd {
switch m.uiState {
case uiMainPage:
return textinput.Blink
case uiIsLoading:
return nil
case uiLoaded:
return nil
}
return nil
}
func initialModel() model {
ti := textinput.New()
ti.Placeholder = "Let me convert your English into code?"
ti.Focus()
ti.CharLimit = 156
ti.Width = 50
ti.Prompt = "🔍 "
return model{
uiState: uiMainPage,
textInput: ti,
err: nil,
}
}
const dummy = `
Today’s Menu
| Name | Price | Notes |
| --- | --- | --- |
| Tsukemono | $2 | Just an appetizer |
| Tomato Soup | $4 | Made with San Marzano tomatoes |
| Okonomiyaki | $4 | Takes a few minutes to make |
| Curry | $3 | We can add squash if you’d like |
Seasonal Dishes
| Name | Price | Notes |
| --- | --- | --- |
| Steamed bitter melon | $2 | Not so bitter |
| Takoyaki | $3 | Fun to eat |
| Winter squash | $3 | Today it's pumpkin |
Desserts
| Name | Price | Notes |
| --- | --- | --- |
| Dorayaki | $4 | Looks good on rabbits |
| Banana Split | $5 | A classic |
| Cream Puff | $3 | Pretty creamy! |
All our dishes are made in-house by Karen, our chef. Most of our ingredients
are from our garden or the fish market down the street.
Some famous people that have eaten here lately:
* [x] René Redzepi
* [x] David Chang
* [ ] Jiro Ono (maybe some day)
Bon appétit!
`
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch m.uiState {
case uiMainPage:
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc":
return m, tea.Quit
case "enter":
m.response = getCommand(m.textInput.Value())
m.uiState = uiLoaded
return m, cmd
}
}
m.textInput, cmd = m.textInput.Update(msg)
return m, cmd
case uiLoaded:
var (
cmd tea.Cmd
cmds []tea.Cmd
)
switch msg := msg.(type) {
case tea.WindowSizeMsg:
headerHeight := lipgloss.Height(m.headerView())
footerHeight := lipgloss.Height(m.footerView())
verticalMarginHeight := headerHeight + footerHeight
if !m.isReady {
m.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight)
m.viewport.YPosition = headerHeight
m.viewport.HighPerformanceRendering = useHighPerformanceRenderer
m.viewport.SetContent(textStyle(dummy))
m.isReady = true
m.viewport.YPosition = headerHeight + 1
} else {
m.viewport.Width = msg.Width
m.viewport.Height = msg.Height - verticalMarginHeight
}
if useHighPerformanceRenderer {
cmds = append(cmds, viewport.Sync(m.viewport))
}
case tea.KeyMsg:
switch msg.String() {
case "q":
return m, tea.Quit
case "ctrl+n":
m.isReady = false
m.response = ""
m.uiState = uiMainPage
m.textInput.Focus()
m.textInput.SetValue("")
case "esc":
m.isReady = false
m.response = ""
m.uiState = uiMainPage
m.textInput.Blink()
m.textInput.SetValue(m.textInput.Value())
}
}
m.viewport, cmd = m.viewport.Update(msg)
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
}
return m, nil
}
func (m model) helpView() string {
return helpStyle("\n ↑/↓: Navigate • q: Quit\n")
}
func (m model) headerView() string {
title := titleStyle.Render(m.textInput.Value())
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(title)))
return lipgloss.JoinHorizontal(lipgloss.Center, title, line)
}
func (m model) footerView() string {
info := infoStyle.Render(fmt.Sprintf("%3.f%%", m.viewport.ScrollPercent()*100))
line := strings.Repeat("─", max(0, m.viewport.Width-lipgloss.Width(info)))
return lipgloss.JoinHorizontal(lipgloss.Center, line, info)
}
func (m model) View() string {
var state string
switch m.uiState {
case uiMainPage:
state =
docStyle(fmt.Sprintf(
textStyle("Commander")+"\n\n%s\n\n\n%s",
m.textInput.View(),
helpStyle("enter: confirm exit • esc: exit\n"),
) + "\n")
case uiIsLoading:
state = fmt.Sprintf("\n %s%s%s\n\n", m.spinner.View(), " ", textStyle("Thinking..."))
case uiLoaded:
state = fmt.Sprintf("%s\n%s\n%s", m.headerView(), m.viewport.View(), m.footerView())
}
return state
}
func main() {
p := tea.NewProgram(initialModel(), tea.WithAltScreen(), tea.WithMouseCellMotion())
if err := p.Start(); err != nil {
log.Fatal(err)
}
} Screen.Recording.2022-08-03.at.14.10.45.mov |
Beta Was this translation helpful? Give feedback.
-
that example does not run, and still has a whole lot more than the minimum needed... my guess would be:
You'd probably need to rework your update to handle that msg regardless of |
Beta Was this translation helpful? Give feedback.
-
I absolutely understand what you mean and your guess is perhaps correct. PS this shouldn't be an issue anymore, i think its more suitable as a discussion |
Beta Was this translation helpful? Give feedback.
-
you could probably always handle that event, and show the viewport or not in the |
Beta Was this translation helpful? Give feedback.
-
Hey @ahmedsaheed did you still need help with this? |
Beta Was this translation helpful? Give feedback.
-
@caarlos0 (cc/ @bashbunni ) I'm facing the same issue. In my case I tried to wrangle the basics example (think a list of options), and when I press enter or [space] to select that option, I go into the pager example. I think what's happening in my case (and ahmedsaheed's case) is calling code block 1 is being hit with a space switch msg := msg.(type) {
case tea.KeyMsg:
// code block 1
case tea.WindowSizeMsg:
// code block 2
} I have a private repo (because it's embarrassingly bad atm), that I can invite you both to. There's no requirements, just a clone and a small config file |
Beta Was this translation helpful? Give feedback.
-
If anyone is having this issue while working with SSH client of gliderlab, make a default case along case tea.WindowSizeMsg, case tea.KeyMsg whatever. Then put a ready bool to your model and initialize it by false. Then put a ssh.Session parameter on your model, comes from when initializing the server. Put the following code into your default case: https://pastebinp.com/hTgfD0Anz31wW60NO6Q#OhLkpEPmm0f-LtBf5xOlyqtrsuKJj8ISgZcM1VRqL1Q= |
Beta Was this translation helpful? Give feedback.
-
For some unknown reasons to me, whenever i try to use the viewport, the terminal must be dragged for it to display.
Could i be doing something wrong?
and in my view i have
Screen.Recording.2022-08-03.at.12.36.06.mov
Beta Was this translation helpful? Give feedback.
All reactions