Skip to content

Commit

Permalink
Merge branch 'charmbracelet:master' into fix/color-escaping-issue-430
Browse files Browse the repository at this point in the history
  • Loading branch information
D7682 committed Mar 8, 2024
2 parents 28ae01b + e3823b2 commit 7c98614
Show file tree
Hide file tree
Showing 17 changed files with 589 additions and 83 deletions.
14 changes: 14 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
* @meowgorithm @maaslalani
cursor/ @maaslalani
filepicker/ @maaslalani
help/ @meowgorithm
key/ @meowgorithm
list/ @muesli
paginator/ @maaslalani
progress/ @meowgorithm
spinner/ @meowgorithm
stopwatch/ @meowgorithm
table/ @maaslalani
textarea/ @maaslalani
textinput/ @meowgorithm
viewport/ @meowgorithm
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ jobs:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
go test -race -covermode atomic -coverprofile=profile.cov ./...
GO111MODULE=off go get github.com/mattn/goveralls
$(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github
go install github.com/mattn/goveralls@latest
goveralls -coverprofile=profile.cov -service=github
2 changes: 1 addition & 1 deletion .github/workflows/lint-soft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
# Optional: golangci-lint command line arguments.
args: --config .golangci-soft.yml --issues-exit-code=0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

- uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
# Optional: golangci-lint command line arguments.
#args:
Expand Down
4 changes: 4 additions & 0 deletions cursor/cursor.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ func (m Model) Mode() Mode {
//
// For available cursor modes, see type CursorMode.
func (m *Model) SetMode(mode Mode) tea.Cmd {
// Adjust the mode value if it's value is out of range
if mode < CursorBlink || mode > CursorHide {
return nil
}
m.mode = mode
m.Blink = m.mode == CursorHide || !m.focus
if mode == CursorBlink {
Expand Down
73 changes: 50 additions & 23 deletions filepicker/filepicker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"

Expand Down Expand Up @@ -35,6 +36,8 @@ func New() Model {
Cursor: ">",
AllowedTypes: []string{},
selected: 0,
ShowPermissions: true,
ShowSize: true,
ShowHidden: false,
DirAllowed: false,
FileAllowed: true,
Expand All @@ -61,7 +64,7 @@ type readDirMsg struct {

const (
marginBottom = 5
fileSizeWidth = 8
fileSizeWidth = 7
paddingLeft = 2
)

Expand Down Expand Up @@ -145,11 +148,13 @@ type Model struct {
// If empty the user may select any file.
AllowedTypes []string

KeyMap KeyMap
files []os.DirEntry
ShowHidden bool
DirAllowed bool
FileAllowed bool
KeyMap KeyMap
files []os.DirEntry
ShowPermissions bool
ShowSize bool
ShowHidden bool
DirAllowed bool
FileAllowed bool

FileSelected string
selected int
Expand Down Expand Up @@ -190,13 +195,13 @@ func newStack() stack {
}
}

func (m Model) pushView() {
m.minStack.Push(m.min)
m.maxStack.Push(m.max)
m.selectedStack.Push(m.selected)
func (m *Model) pushView(selected, min, max int) {
m.selectedStack.Push(selected)
m.minStack.Push(min)
m.maxStack.Push(max)
}

func (m Model) popView() (int, int, int) {
func (m *Model) popView() (int, int, int) {
return m.selectedStack.Pop(), m.minStack.Pop(), m.maxStack.Pop()
}

Expand Down Expand Up @@ -243,7 +248,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
break
}
m.files = msg.entries
m.max = m.Height - 1
m.max = max(m.max, m.Height-1)
case tea.WindowSizeMsg:
if m.AutoHeight {
m.Height = msg.Height - marginBottom
Expand Down Expand Up @@ -347,7 +352,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
}

m.CurrentDirectory = filepath.Join(m.CurrentDirectory, f.Name())
m.pushView()
m.pushView(m.selected, m.min, m.max)
m.selected = 0
m.min = 0
m.max = m.Height - 1
Expand All @@ -360,22 +365,19 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
// View returns the view of the file picker.
func (m Model) View() string {
if len(m.files) == 0 {
return m.Styles.EmptyDirectory.String()
return m.Styles.EmptyDirectory.Height(m.Height).MaxHeight(m.Height).String()
}
var s strings.Builder

for i, f := range m.files {
if i < m.min {
if i < m.min || i > m.max {
continue
}
if i > m.max {
break
}

var symlinkPath string
info, _ := f.Info()
isSymlink := info.Mode()&os.ModeSymlink != 0
size := humanize.Bytes(uint64(info.Size()))
size := strings.Replace(humanize.Bytes(uint64(info.Size())), " ", "", 1)
name := f.Name()

if isSymlink {
Expand All @@ -385,9 +387,16 @@ func (m Model) View() string {
disabled := !m.canSelect(name) && !f.IsDir()

if m.selected == i {
selected := fmt.Sprintf(" %s %"+fmt.Sprint(m.Styles.FileSize.GetWidth())+"s %s", info.Mode().String(), size, name)
selected := ""
if m.ShowPermissions {
selected += " " + info.Mode().String()
}
if m.ShowSize {
selected += fmt.Sprintf("%"+strconv.Itoa(m.Styles.FileSize.GetWidth())+"s", size)
}
selected += " " + name
if isSymlink {
selected = fmt.Sprintf("%s%s", selected, symlinkPath)
selected += "" + symlinkPath
}
if disabled {
s.WriteString(m.Styles.DisabledSelected.Render(m.Cursor) + m.Styles.DisabledSelected.Render(selected))
Expand All @@ -408,10 +417,21 @@ func (m Model) View() string {
}

fileName := style.Render(name)
s.WriteString(m.Styles.Cursor.Render(" "))
if isSymlink {
fileName = fmt.Sprintf("%s → %s", fileName, symlinkPath)
fileName += " → " + symlinkPath
}
if m.ShowPermissions {
s.WriteString(" " + m.Styles.Permission.Render(info.Mode().String()))
}
if m.ShowSize {
s.WriteString(m.Styles.FileSize.Render(size))
}
s.WriteString(fmt.Sprintf(" %s %s %s", m.Styles.Permission.Render(info.Mode().String()), m.Styles.FileSize.Render(size), fileName))
s.WriteString(" " + fileName)
s.WriteRune('\n')
}

for i := lipgloss.Height(s.String()); i <= m.Height; i++ {
s.WriteRune('\n')
}

Expand Down Expand Up @@ -494,3 +514,10 @@ func (m Model) canSelect(file string) bool {
}
return false
}

func max(a, b int) int {
if a > b {
return a
}
return b
}
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ module github.com/charmbracelet/bubbles
go 1.18

require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/atotto/clipboard v0.1.4
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/harmonica v0.2.0
github.com/charmbracelet/lipgloss v0.9.1
github.com/charmbracelet/lipgloss v0.10.0
github.com/dustin/go-humanize v1.0.1
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/mattn/go-runewidth v0.0.15
github.com/muesli/reflow v0.3.0
github.com/muesli/termenv v0.15.2
github.com/rivo/uniseg v0.4.4
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f
github.com/rivo/uniseg v0.4.7
github.com/sahilm/fuzzy v0.1.1
)

require (
Expand Down
16 changes: 10 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
Expand All @@ -6,8 +10,8 @@ github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
Expand All @@ -33,10 +37,10 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y=
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
7 changes: 3 additions & 4 deletions list/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type DefaultItem interface {
```

You can see a working example in our [Kancli][kancli] project built
explicitly for a tutorial on lists and composite views in Bubble Tea.
explicitly for a tutorial on lists and composite views in Bubble Tea.

[VIDEO](https://youtu.be/ZA93qgdLUzM)

Expand Down Expand Up @@ -64,9 +64,8 @@ example][listDefault].
For full control over the way list items are rendered you can also define your
own `ItemDelegate` too ([example][customDelegate]).


[kancli]: https://github.com/charmbracelet/kancli/blob/main/main.go#L45
[itemDelegate]: https://pkg.go.dev/github.com/charmbracelet/bubbles@v0.10.2/list#ItemDelegate
[itemDelegate]: https://pkg.go.dev/github.com/charmbracelet/bubbles/list#ItemDelegate
[replacedLine]: https://github.com/charmbracelet/bubbletea/blob/master/examples/list-default/main.go#L77
[listDefault]: https://github.com/charmbracelet/bubbletea/tree/master/examples/list-default
[customDelegate]: https://github.com/charmbracelet/bubbletea/blob/a6f46172ec4436991b90c2270253b2d212de7ef3/examples/list-simple/main.go#L28-L49
[customDelegate]: https://github.com/charmbracelet/bubbletea/blob/master/examples/list-simple/main.go#L29-L50
4 changes: 2 additions & 2 deletions list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,12 +532,12 @@ func (m *Model) CursorDown() {
}

// PrevPage moves to the previous page, if available.
func (m Model) PrevPage() {
func (m *Model) PrevPage() {
m.Paginator.PrevPage()
}

// NextPage moves to the next page, if available.
func (m Model) NextPage() {
func (m *Model) NextPage() {
m.Paginator.NextPage()
}

Expand Down
Loading

0 comments on commit 7c98614

Please sign in to comment.