charmbracelet / bubbles Goto Github PK
View Code? Open in Web Editor NEWTUI components for Bubble Tea 🫧
License: MIT License
TUI components for Bubble Tea 🫧
License: MIT License
We already have text input.
A text input field, akin to an <input type="text"> in HTML. Supports unicode, pasting, in-place scrolling when the value exceeds the width of the element and the common, and many customization options.
It would be nice if we have some components akin to <input type="number">
, correspond to intinput
and floatinput
in bubbletea. They only accept valid number input.
And what I want most is boolinput
, which can only let user input y | n | yes | no | t | f | 0 | 1 | true | false
etc.
Currently I think of two ways to accomplish this goal:
textinput
Btw, all input should know if itself is canceled which is different from zero value(like empty string), because some programs should be terminated if user cancel a prompt.
Tried with https://github.com/charmbracelet/bubbletea/tree/master/examples/pager
If the height is less than 6, than it got panic in the pager view:
height=5
got panic errors:
bash-3.2$ ./one-pager
Caught panic:
runtime error: slice bounds out of range [:-1]
Restoring terminal...
goroutine 1 [running]:
runtime/debug.Stack(0x56, 0x0, 0x0)
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/debug/stack.go:24 +0x9f
runtime/debug.PrintStack()
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/debug/stack.go:16 +0x25
github.com/charmbracelet/bubbletea.(*Program).Start.func1(0xc0000743c0)
/Users/mas/go/pkg/mod/github.com/charmbracelet/[email protected]/tea.go:119 +0xd3
panic(0x1104200, 0xc0000b4000)
/usr/local/Cellar/go/1.15.2/libexec/src/runtime/panic.go:969 +0x175
github.com/charmbracelet/bubbles/viewport.Model.visibleLines(...)
/Users/mas/go/pkg/mod/github.com/charmbracelet/[email protected]/viewport/viewport.go:81
github.com/charmbracelet/bubbles/viewport.View(0x78, 0xffffffffffffffff, 0x0, 0x3, 0x0, 0xc000080480, 0x45, 0x45, 0x0, 0x45)
/Users/mas/go/pkg/mod/github.com/charmbracelet/[email protected]/viewport/viewport.go:366 +0x24d
main.model.View(0xc000136000, 0x642, 0x1, 0x78, 0xffffffffffffffff, 0x0, 0x3, 0x0, 0xc000080480, 0x45, ...)
/Users/mas/go/src/bitbucket.org/demo-learn/app/one-pager/main.go:157 +0x56e
github.com/charmbracelet/bubbletea.(*Program).Start(0xc0000743c0, 0x0, 0x0)
/Users/mas/go/pkg/mod/github.com/charmbracelet/[email protected]/tea.go:216 +0x67d
main.main()
/Users/mas/go/src/bitbucket.org/demo-learn/app/one-pager/main.go:66 +0x2d4
Hello,
I'm unable to get
this library due to the following error:
go get github.com/charmbracelet/bubbles/textinput
# github.com/charmbracelet/bubbles/textinput
../../go/pkg/mod/github.com/charmbracelet/[email protected]/textinput/textinput.go:400:16: impossible type assertion:
Model does not implement tea.Model (missing Init method)
I've also tried getting other versions (6.0.0, 5.0.1) but they all return the same error.
At least in Konsole/Linux, the Home/End/Del keys don't work inside text inputs. Del creates opening brackets ([
) that aren't counted in cursor movement, and the other two do nothing at all.
I am loving this project, but one thing that keeps me from replacing tview is the lack of a table widget. It would be like a list widget but 2d and track cell selection.
Currently, the list filter is using the fuzzy.Find
for finding matches. This works perfectly in most cases. Whilst, in some special cases when the targets are some long ID forms, e.g.:
- /subscriptions/0000000-0000-0000-0000-00000000000/resourceGroups/example-rg/providers/Microsoft.Network/networkInterfaces/example-nic
- /subscriptions/0000000-0000-0000-0000-00000000000/resourceGroups/example-rg/providers/Microsoft.Network/virtualNetworks/example-network/subnets/internal
(From: Azure/aztfexport#79)
If user wants to filter for subnets
, which expects to be the 2nd one, however, fuzzy matches both, and even ranking the first one as a better match than the second one.
Fuzzy match works well in case each target is a single word. But it brings suprise otherwise. In multi word form, it would be great to allow users to specify other matching strategy than fuzzy, e.g. regexp, exact match, etc.
It would add lots of value to be able to search a document for keywords. Similar to how we filter lists or use /
in vim
Is it possible to create a File Picker Bubble that could be easily used?
I would imagine a cursor and selection that could be moved around using arrow keys and a tree like view for files/folders
Including multi-line items with empty spaces and lines causes the list component to behave oddly. Lines appear and disappear as you move the selection up and down.
I didn't narrow this down to the exact characterstics that cause the problem, but it's easy to reproduce.
Take the default list example
Add this item at the beginning of the slice in main()
:
item{title: "Wait a moment", desc: `This item here
Has indentation
Many lines
Some of them blank
This causes text to appear
and disappear as the cursor moves up
and down
`},
Move a few places down the list, then up again. It's impossible to miss.
progress
currently has the option to define a custom gradient using WithGradient
, which accepts two colors as strings. These are then passed to colorful.Hex
– which (perhaps obviously) doesn’t accept ANSI colors. Thus, creating ANSI gradients (for example, from 5
to 13
, regular to bright magenta) isn’t supported and the bar will fall back to a black fill.
On the other hand, passing ANSI colors to WithSolidFill
works perfectly, as it is not run through colorful.Hex
before rendering.
go-colorful
, the library used to generate the gradient for progress
, does not currently work with ANSI colors.
Hi guys,
Do you have any plan to implement Table widgets for Bubble Tea? Or a little hack with the "Viewpoint" widget to support simple tables?
Thanks for your great works!
👋🏽 hi, awesome work on the whole bubbletea framework!
I was wondering what would be the tea
semantic way to incorporate a timer into a tea application. I want the app to display the time that is left and for the it to exit gracefully once the timer is done.
I looked under the hood of the Spinner, given that it ticks at at regular interval, as a base for a ticker component. I spotted the tea.Tick
function which looks promising.
When I set initial value for an input:
func initialModel() model {
ti := textinput.NewModel()
ti.SetValue("Pikachu")
ti.Focus()
ti.CharLimit = 156
ti.Width = 20
return model{
textInput: ti,
err: nil,
}
}
The cursor will be at 'P' because of this:
// SetValue sets the value of the text input.
func (m *Model) SetValue(s string) {
// ...
// m.pos = 0
if m.pos > len(m.value) {
m.SetCursor(len(m.value))
}
m.handleOverflow()
}
Is this expected or a bug?
If you start off a list with a single (or 0) pages, and then update the list of items where more than one page is required, the pagination buttons are disabled.
Current workaround is to do this after you update the list of items:
list.SetFilteringEnabled(list.FilteringEnabled())
which as the last step refreshes the keybinds.
I would like to disable the blinking cursor in the textinput widget. It looks like all the parts are there to do it, but none of them are exposed. I'm willing to send a pull request for this, but I'm not sure what the best way to go about this would be, so I wanted to ask first.
Tentatively wrapping the two calls to m.blinkCmd() in Update() seems like the quickest way, but I'm not sure if you wanted to expand the class to allow for a better way to set this, maybe by promoting Model.cursorMode and respecting it's state.
I want to use the text input bubble to allow the user to enter some notes. They can enter newlines in the notes if they want. It looks like the text input component ignores the Enter key event. Is it possible to add multi-line support so that gets translated to "\n"? Or is there a more appropriate component for this?
Add option to hide input for sensitive strings such as passphrases or passwords. like type="password" in html.
Thanks for developing this cool library!
I am trying to create something similar to list-fancy
example where both title and description should be filtered when pressing /
. It seems to be a really hard task since list.Model.filteredItems
is a private field. Does it make sense to add a getter i.e. list.Model.FilteredItems()
? Or it is possible without using list.Model.filteredItems
?
When you disable the help and quit bindings of the list widget, for example with the following:
listModel := list.NewModel([]list.Item{}, list.NewDefaultDelegate(), 0, 0)
listModel.SetShowHelp(false)
listModel.DisableQuitKeybindings()
listModel.KeyMap.ShowFullHelp.SetEnabled(false)
listModel.KeyMap.CloseFullHelp.SetEnabled(false)
The help and quit bindings get re-enabled by entering and exiting filtering mode.
These bugs are caused by the updateKeyBindings method setting the bindings to enabled after ending filtering, regardless of their current state.
This bug is annoying if you are handling help and quit bindings yourself, and causes the SetShowHelp and DisableQuitKeybindings methods to not work as they are described in the documentation.
hello, I come from a project (ticker
) that uses bubbles/viewport
to display its main contents.
we noticed that when the content doesn't fit on a single page and you scroll at the bottom, bubbles/viewport
doesn't render the last line of content if it doesn't end with a new line \n
character (here the issue #158 reported on ticker
).
the problem is reproducible with bubbletea
's pager example that uses bubbles/viewport
, for example:
$ git clone https://github.com/charmbracelet/bubbletea.git
...
$ cd bubbletea/examples/pager/
$ go build
$ ls -1
artichoke.md # file displayed in the example
main.go
pager*
$ tail -1 artichoke.md | xxd | tail -1
00000030: 2069 6e20 5370 616e 6973 682e 0a in Spanish.. # ends with new line
$ ./pager
everything looks fine, now I remove last new line \n
character from artichoke.md
:
$ truncate -s -1 artichoke.md
$ tail -1 artichoke.md | xxd | tail -1
00000030: 2069 6e20 5370 616e 6973 682e in Spanish.
$ ./pager
and the last line
_Alcachofa_, if you were wondering, is artichoke in Spanish.
is not displayed anymore.
unfortunately I don't have a patch, I suspect it's an off-by-one error because I see lots of len(m.lines)-1
in viewport.go
and I think it could be related to the problem, but I wasn't able to completely figure it out.
Hello,
It seems there is missing functions calls in the code snippet for the Keys section
In the code snippet provided:
var DefaultKeyMap = KeyMap{
Up: key.NewBinding(
key.WithKeys("k", "up"), // actual keybindings
key.WithHelp("↑/k", "move up"), // corresponding help text
),
Down: key.NewBinding(
WithKeys("j", "down"),
WithHelp("↓/j", "move down"),
),
}
On the Down element, WithKeys
and WithHelp
are not defined, It should be calling key.WithKeys
and key.WithHelp
instead
If this is intended, which one is considered correct?
Thanks
Hello,
m.textInput.SetValue(fmt.Sprintf("%s |a word|", m.textInput.Value()))
m.textInput.CursorEnd() // sets cursor on last character, so next input goes _before_ last character
Couldn't use setCursor(pos)
as workaround due to imp of it.
Also why pos
is private? I need to find if the cursor is inside a |
block. Is there a way to achieve this without accessing pos
?
i.e. very common calendar widget on web
I think we have an unwanted extra space on the Dot spinner, here:
Line 25 in 0ac5ecd
Is this intended ?
If not, I can submit a PR.
Hey guys,
when using list to show and filter a list of items it would be handy to be able to not only set items programmatically, but also set the FilterValue
and triggering filtering programmatically.
Currently we have:
// FilterValue returns the current value of the filter.
func (m Model) FilterValue() string {
return m.FilterInput.Value()
}
so the FilterValue is directly tied to the FilterInput
. I could theoretically hand everything down to the FilterInput
, but that would be very tedious, when I have an external separate TextInput which might set the filter.
Especially, when the filterInput sets this:
filterInput.Prompt = "Filter: "
- so there is no way to customize this.
So my wishlist would be:
SetFilterValue
-funcSetLiveFilteringEnabled
-func which determines if the list is automatically filtered via FilterValue
Filter
-func that actually triggers filtering via FilterValue
Thanks for the awesome work!
I'd like to be able to see the system cursor in my app.
Is it possible? Thanks.
Hi,
You broke your own tool glow by introducing a breaking change in a patch version.
See documentation for correctly using semver. https://golang.org/ref/mod#versions
Hope it helps, gook luck :)
Can we make something like this one?
Or even adopt this package, idk. I asking cause maybe someone already has implemented stuff like this, and can share it. Also, if someone is interest in this idea, i can maybe implement it. Anyway bubbltea requires more prompt stuff.
Hi, Bubbles is a really cool library with some easy-to-use plugin to use in bubble-tea.
I tried to play a bit with the timer, which currently display the timeout duration in Hour,Min,Sec,MilliSeconds.
But there could be some use case (and I have one) where the amount of hour is just too big so it could be great to display days and month as well.
It could be either by having the timer handling it automatically or having a way to customize its behaviour for the user.
Currently the status bar presents a fixed message with X items
as highlighted in the image
It could be interesting the possibility to customize the label item(s)
Here is the reference in the code
Line 1023 in 18d2545
What do you think about ? (I can provide a PR about this)
I'm playing with the pager example over in the Bubbletea repo. I noticed the call:
m.viewport.SetContent(m.content)
appears in the Update
func. Doing this sort of side effect in Update
seems odd to me, so I tried moving it to View
, but in that case, the viewport stops responding to input. I'm not sure View
is any better of a place to call SetContent
, but I just want to understand what is going in here and if updating the viewport content in Update
is the way to go always.
Thanks!
bubbletea has recently changed the KeyType for the space character.
As a result, in particular, nothing happens when the user enters space in the textinput
component.
We need to add a case tea.KeySpace:
somewhere around these lines.
bubbles revision is 292a1dd7ba97b1dc96a12d5ba50301cc731ef37f
(current master
)
Is there an easy way of detecting key combinations, similar to how vim key combos work?
I'm guessing I can implement something myself by recording the time between key presses and all that.
The use case is to allow more complex keybindings in a program that are easier to remember.
Prefixing key combos with something like vim's <leader>
key, or global actions with g.
I would like to have a fuzzy filter in list
which does not change the order of the items. Currently sahilm/fuzzy is being used. Can you provide an interface so that the user can choose a different fuzzy finder library or implementation?
List will always keep this gap open, even if Title
and Spinner
are disabled.
That makes it less flexible to use. It should be able to appear completely compact, if you choose to.
SetShowSpinner
-func that lets you disable itHow to use the progress component to show download progress. I have tried couple of things but in vain. Can someone provide an example?
When storing multiple textinput.Model
s in a slice, like in the official example textinputs
.
If we update the Update
function like so:
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "esc":
return m, tea.Quit
// Change cursor mode
case "ctrl+r":
m.cursorMode++
if m.cursorMode > textinput.CursorHide {
m.cursorMode = textinput.CursorBlink
}
cmds := make([]tea.Cmd, len(m.inputs))
for i := range m.inputs {
cmds[i] = m.inputs[i].SetCursorMode(m.cursorMode)
}
return m, tea.Batch(cmds...)
+ case "ctrl+q":
+ before := m.inputs[:m.focusIndex]
+ after := m.inputs[m.focusIndex:]
+ line := textinput.NewModel()
+
+ before = append(before, line)
+ before = append(before, after...)
+ m.inputs = before
// Set focus to next input
case "tab", "shift+tab", "enter", "up", "down":
s := msg.String()
// Did the user press enter while the submit button was focused?
// If so, exit.
if s == "enter" && m.focusIndex == len(m.inputs) {
return m, tea.Quit
}
// Cycle indexes
if s == "up" || s == "shift+tab" {
m.focusIndex--
} else {
m.focusIndex++
}
if m.focusIndex > len(m.inputs) {
m.focusIndex = 0
} else if m.focusIndex < 0 {
m.focusIndex = len(m.inputs)
}
cmds := make([]tea.Cmd, len(m.inputs))
for i := 0; i <= len(m.inputs)-1; i++ {
if i == m.focusIndex {
// Set focused state
cmds[i] = m.inputs[i].Focus()
m.inputs[i].PromptStyle = focusedStyle
m.inputs[i].TextStyle = focusedStyle
continue
}
// Remove focused state
m.inputs[i].Blur()
m.inputs[i].PromptStyle = noStyle
m.inputs[i].TextStyle = noStyle
}
return m, tea.Batch(cmds...)
}
}
// Handle character input and blinking
cmd := m.updateInputs(msg)
return m, cmd
}
After pressing ctrl+q
, two lines are blanked.
Thanks for reading this!
I'm trying to use the list bubble to render a table.
I am doing it with a custom delegate, but I'am having problems to render the table header (column names) since I cannot place it where I want.
So far I can disable the title, status bar and filter and also remove paddings to insert the table header on top of the whole list, but that is not ideal.
Having a "slot" where I could place some content just above the populated view would be ideal.
Expected behaviours:
The above are default behaviours in most linux and windows text editing environments. It would be nice to have them respected by the textinput
.
Having spent 3 minutes reading the textinput.Update, I see that a lot of care has gone into handling some specific cases of input for the textinput
bubble.
Having spent 5 minutes working in a local fork, I see that keystrokes do not come with Ctrl
modifiers in the same way as Alt
modifiers, and that the specific KeyCtrlN
values are for letters only, and do not include the needed values for the above updates.
Is it correct to assume that there is some technical reason why Ctrl
hasn't received a similar treatment as Alt
?
Is access to the state of ctrl
being worked on?
Thanks
I am building a command line tool that collect some user inputs. Some of them are sensitive. Like secrets and tokens. I don't know how to hide these information when typing. Both hiding the input or showing some asterisks will be fine.
If there is a easy way that I don't know can achieve this or textinput just doesn't support this yet?
I'm looking to enable filtering for my github.com/charmbracelet/bubbles/list
component by default so that as soon as the list is rendered I can start to type, without needing to press the filter shortcut (/
) first.
list-default
example within the charmbracelet/bubbletea repom.list.SetFilteringEnabled(true)
on line 82I'm relatively new to the package so I think this needs to be done at a different point within the model lifecycle, rather than at the point of creation. Any help would be great 👍
I've used the list for only a couple of occations now, but I've come to think that using the list would be more convenient if FilterValue were in the ItemDelegate (or some delegate) instead of in list.Item. Currently we have to copy the item array and wrap each item into a type that implements FilterValue, unless it is possible to change the client's item type directly.
Also a multiline answer. I would definitely see myself using them on https://github.com/chriswalz/bit.
Right now I'm using https://github.com/AlecAivazis/survey
Allow horizontal scrolling if viewport content is wider than its width.
It would be nice if the viewport provided some options to automatically wrap and truncate text to keep layouts from breaking, rather than leaving this as an exercise for the user.
The most likely solution here is to take advantage of reflow.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.