Skip to content

Implemented bubbles list widget #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 73 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
0ab2af9
started implementing list Module
Nov 4, 2020
400d07b
wrote line wraping
Nov 4, 2020
5edffcb
Handled color of current and selected lines
Nov 4, 2020
c2eee8b
added lineCurserOffset to keep the current line within the borders
Nov 4, 2020
7df79da
added left padding of seperators
Nov 4, 2020
bc6de77
added methode for returning the selected items within a list
Nov 4, 2020
07b56d9
formated code
Nov 4, 2020
7fc7a27
turned wrap back on and deleted done todo "test sep.. Width"
Nov 4, 2020
51fec9f
simplefied line writing into buffer
Nov 4, 2020
eb0a940
Fixed Hightlighting bug
Nov 4, 2020
ac40b51
Added tests, changed item-line-wraping, made configs-public
Nov 4, 2020
6c091f0
changed hightlighting from string to termenv.Style
Nov 4, 2020
5ea572d
Implementet a prefix for selected line
Nov 4, 2020
3208db5
made the List Model satisfy the Sort interface
Nov 4, 2020
59d748b
found bug: when piping into this example: error: EOF
Nov 4, 2020
415b561
Changed Example from pipe to "tutorial"-lines
Nov 4, 2020
336a0c8
added dynamic Test for testing View after list-methodes
Nov 4, 2020
5c86993
implemented Bottom movement and fixed the example
Nov 4, 2020
32e40ff
changed creation of the line and wrap prefix
Nov 4, 2020
53d84f2
fixed offrunning bug, added and changed tests
Nov 4, 2020
88e9fae
tryed to get TestPanic to work and updated question
Nov 4, 2020
826f05d
Droped Viewport from list Model, implemented more methodes on list
Nov 4, 2020
5aebe7d
Implemented Lines(), fixed Move methode
Nov 4, 2020
e8bc6b5
changed Style handling and implemented jump
Nov 4, 2020
da31b5f
renaming local variables, add configurability, changing test samples
Nov 4, 2020
f283493
changed to interface fmt.Stringer within item struct
Nov 4, 2020
9affa83
Added "Equals" handling and Error types
Nov 4, 2020
a1cd761
udapted to breaking API-change
Nov 15, 2020
eaa09c5
Added new Method's and new error type
Nov 4, 2020
1586ba1
tryed to fix bug, but still dont understand bug
Nov 4, 2020
21fc43c
reset to Move methode handeling the visible Offset
Nov 4, 2020
ae4cd79
tried to handel visibile offset and enabled logging
Nov 4, 2020
aff3409
New try to implement a dedicated methode for cursor movement
Nov 4, 2020
8dea4b5
Implemented keepVisibleWrap
Nov 4, 2020
9fce841
working Movement without wrap
Nov 4, 2020
550bbb2
Up and Down Movement with wrap are working
Nov 4, 2020
8509ad1
Working Movement with zero offset, but not with more
Nov 4, 2020
60bbc8a
fixed visible Offset within up movement
Nov 4, 2020
7dec032
fixed ToggleSelect
Nov 4, 2020
d570858
removed log statements and fixed extrem cases in ToggleSelect
Nov 4, 2020
7d35d55
refined doc-strings, added new struct, fixed bit of bug
Nov 4, 2020
0de39ef
replaced single fields about vis and cursor position
Nov 4, 2020
c24dd82
Changed from String field within List-Model to Prefix-Closure
Nov 4, 2020
029315c
Changed prefix closure to interface
Nov 4, 2020
1dc694a
Changed Pre/suffixer interface, implemented suffixer support
Nov 4, 2020
b126f16
fixed lineOffset-bug and some typos
Nov 4, 2020
1496436
Made View() functional and changed list-Model field
Nov 6, 2020
8fcf482
research bugs, found some, but not yet all fixed
Nov 12, 2020
c416b54
refactored into dedicated files
Nov 12, 2020
7857dc9
Rewrote Tests to be more specific
Nov 13, 2020
81eb395
Added more test and removed there by found bugs
Nov 15, 2020
17a7494
made some list-Methods fail **silently** and not panic,
Nov 17, 2020
2fd5173
Made example list editable and changed a function interface
Nov 17, 2020
7062543
change keybindings within example and added second sort function
Nov 18, 2020
43990eb
Changed list items to have a unique id
Nov 18, 2020
71e9791
Changes Lines/View to be inherently bound to contain the Cursor
Nov 19, 2020
a1d3edb
excluded nil values from list and empty string from View
Nov 21, 2020
e62fe46
Changed Wrap from bool to int and handling of empty suffix
Nov 25, 2020
00e1716
fixed lineOffset bug and made list output fill the screen
Nov 30, 2020
34a1143
Renamed methods and added Method to change selected state
Dec 3, 2020
5a5e215
Move select-methods to own file to delete them
Dec 4, 2020
c91d086
removed select field from list item struct
Dec 4, 2020
44cfb7b
moved parts of Lines() Method to own function
Dec 5, 2020
29399c9
Changed Lines() to fail silently (not panic)
Dec 5, 2020
c2dc5ac
Changed Method return types from error to tea.Cmd
Dec 5, 2020
0397a73
Changed Lines to be a function and to return a error
Dec 11, 2020
12d5016
Fixed cursor changing bug within RemoveIndex
Dec 26, 2020
cf474cc
changed Suf- and Prefixer interfaces
Dec 26, 2020
8bff7c8
changed sort return Cmd and renamed a message struct
Jan 5, 2021
1ae4865
added some more (simple) examples
Jan 7, 2021
b29aaba
handled errors within main method and removed redundant interface
Jan 7, 2021
840b01a
added and changed tests to accommodate change of prefix runes
Jan 7, 2021
d3b756e
changed Prefix Methode of *fixer interfaces
Jan 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ go 1.13
require (
github.com/atotto/clipboard v0.1.2
github.com/charmbracelet/bubbletea v0.12.2
github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687
github.com/mattn/go-runewidth v0.0.9
github.com/muesli/reflow v0.1.1-0.20200715144030-a312cb5b2d8d
github.com/muesli/termenv v0.7.4
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 // indirect
golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687 h1:bWXum+xWafUxxJpcXnystwg5m3iVpPYtrGJFc1rjfLc=
github.com/jinzhu/copier v0.0.0-20201025035756-632e723a6687/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/muesli/reflow v0.1.1-0.20200715144030-a312cb5b2d8d h1:ok5jhmKQze1yERN73u46EZhUH4vgC1z4qfeFJ8iOwvg=
github.com/muesli/reflow v0.1.1-0.20200715144030-a312cb5b2d8d/go.mod h1:I9bWAt7QTg/que/qmUCJBGlj7wEq8OAFBjPNjc6xK4I=
github.com/muesli/termenv v0.7.2 h1:r1raklL3uKE7rOvWgSenmEm2px+dnc33OTisZ8YR1fw=
github.com/muesli/termenv v0.7.2/go.mod h1:ct2L5N2lmix82RaY3bMWwVu/jUFc9Ule0KGDCiKYPh8=
github.com/muesli/termenv v0.7.4 h1:/pBqvU5CpkY53tU0vVn+xgs2ZTX63aH5nY+SSps5Xa8=
Expand All @@ -30,6 +35,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a h1:e3IU37lwO4aq3uoRKINC7JikojFmE5gO7xhfxs8VC34=
golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
201 changes: 201 additions & 0 deletions list/example/checkboxes/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package main

import (
"fmt"
"os"
"strconv"

"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
)

// DISCLAIMER: This is not a template but a example.
// This code is NOT performant or good for any other purpose except to show the possibility's of the list bubble.

func main() {
m := model{}
m.vis = list.NewModel()
m.vis.PrefixGen = NewPrefixer()
m.head = "My TODO list!\n============="
m.AddItems([]string{
"buying eggs",
"take the trash out",
"get a hair cut",
"be nice\nto the neighbours",
"get milk",
})
m.tail = "============================================\nuse ' ' to change the done state of a item\nuse 'q' or 'ctrl+c' to exit"
p := tea.NewProgram(m)
if err := p.Start(); err != nil {
fmt.Println("could not run program:", err)
os.Exit(1)
}
}

type item struct {
selected bool
content string
id int
}

func (m item) String() string {
return m.content
}

type model struct {
vis list.Model
jump string
ready bool
head string
tail string
}

func (m model) Init() tea.Cmd {
return nil
}

// update recives messages and the model and changes the model accordingly to the messages
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.vis.PrefixGen == nil {
// use default
m.vis.PrefixGen = NewPrefixer()
}

switch msg := msg.(type) {
case tea.KeyMsg:

// Ctrl+c exits
if msg.Type == tea.KeyCtrlC {
return m, tea.Quit
}
keyString := msg.String()
switch keyString {
case "q":
return m, tea.Quit
case "1", "2", "3", "4", "5", "6", "7", "8", "9", "0":
m.jump += keyString
return m, nil
case "down", "j":
m.vis.MoveCursor(m.popJump(1))
return m, nil
case "up", "k":
m.vis.MoveCursor(-m.popJump(1))
return m, nil
case "r":
d, ok := m.vis.PrefixGen.(*SelectPrefixer)
if ok {
d.NumberRelative = !d.NumberRelative
}
return m, nil
case "J":
m.vis.MoveItem(m.popJump(1))
return m, nil
case "K":
m.vis.MoveItem(-m.popJump(1))
return m, nil
case "t", "home":
j := m.popJump(0)
if j > 0 {
j--
}
m.vis.Top()
m.vis.MoveCursor(j)
return m, nil
case "b", "end":
j := m.popJump(0)
if j > 0 {
j--
}
m.vis.Bottom()
m.vis.MoveCursor(-j)
return m, nil
case "w":
m.vis.Wrap = m.popJump(0)
return m, nil
case "s":
less := func(a, b fmt.Stringer) bool { return a.String() < b.String() }
m.vis.SetLess(less)
m.vis.Sort()
return m, nil
case "o":
less := func(a, b fmt.Stringer) bool {
d, _ := a.(item)
e, _ := b.(item)
return d.id < e.id
}
m.vis.SetLess(less)
m.vis.Sort()
return m, nil
case " ":
updater := func(a fmt.Stringer) (fmt.Stringer, tea.Cmd) {
i, ok := a.(item)
if !ok {
return a, nil
}
i.selected = !i.selected
return i, nil
}
i, _ := m.vis.GetCursorIndex()
cmd := m.vis.UpdateItem(i, updater)
return m, cmd
default:
// resets jump buffer to prevent confusion
m.jump = ""

// pipe all other commands to the update from the vis
l, newMsg := m.vis.Update(msg)
vis, _ := l.(list.Model)
m.vis = vis
return m, newMsg
}

case tea.WindowSizeMsg:

width := msg.Width
height := msg.Height
m.vis.Screen.Width = width
m.vis.Screen.Height = height

if !m.ready {
// Since this program can use the full size of the viewport we need
// to wait until we've received the window dimensions before we
// can initialize the viewport. The initial dimensions come in
// quickly, though asynchronously, which is why we wait for them
// here.
m.ready = true
}
return m, nil

default:
// pipe all other commands to the update from the vis
l, newMsg := m.vis.Update(msg)
vis, _ := l.(list.Model)
m.vis = vis
return m, newMsg
}
}

func (m model) View() string {
return fmt.Sprintf("%s\n%s\n%s", m.head, m.vis.View(), m.tail)
}
func (m *model) AddItems(toAdd []string) {
strList := make([]fmt.Stringer, len(toAdd))
for i, str := range toAdd {
strList[i] = item{content: str}
}
m.vis.AddItems(strList)
}

// popJump takes default vaule and returns the integer value of the jump string
// if its empty or fails the default is returned.
func (m *model) popJump(dft int) int {
if m.jump == "" {
return dft
}
j, err := strconv.Atoi(m.jump)
if err != nil {
return dft
}
m.jump = ""
return j
}
Loading