From 105d88a7282a810529c37f08fa7c03392860a80e Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Mon, 12 Aug 2024 17:33:57 -0400 Subject: [PATCH 01/61] fix(ci): skip CI for examples/tutorials running go1.18 --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fabbf102f3..7f82f8c43a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,16 +31,19 @@ jobs: run: go test ./... - name: Build examples + if: ${{ matrix.go-version != '~1.18' }} run: | go mod tidy go build -v ./... working-directory: ./examples - name: Test examples + if: ${{ matrix.go-version != '~1.18' }} run: go test -v ./... working-directory: ./examples - name: Build tutorials + if: ${{ matrix.go-version != '~1.18' }} run: | go mod tidy go build -v ./... From af7ec0e18715822e820af786e48d71bb069d8e45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 12:41:01 +0000 Subject: [PATCH 02/61] chore(deps): bump github.com/charmbracelet/bubbles in /examples (#1104) --- examples/go.mod | 10 +++++----- examples/go.sum | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index d7f3833f93..af11894936 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,8 +5,8 @@ go 1.21 toolchain go1.22.5 require ( - github.com/charmbracelet/bubbles v0.18.0 - github.com/charmbracelet/bubbletea v0.26.2 + github.com/charmbracelet/bubbles v0.19.0 + github.com/charmbracelet/bubbletea v0.27.0 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/harmonica v0.2.0 github.com/charmbracelet/lipgloss v0.13.0 @@ -23,7 +23,7 @@ require ( github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/x/ansi v0.1.4 // indirect - github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a // indirect + github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/input v0.1.0 // indirect github.com/charmbracelet/x/term v0.1.1 // indirect github.com/charmbracelet/x/windows v0.1.0 // indirect @@ -32,14 +32,14 @@ require ( github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/gorilla/css v1.0.1 // indirect github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect + github.com/sahilm/fuzzy v0.1.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect diff --git a/examples/go.sum b/examples/go.sum index e3367b5364..f75c3fb423 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,3 +1,5 @@ +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= @@ -12,8 +14,8 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= -github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbles v0.19.0 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0= +github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= @@ -22,8 +24,8 @@ github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30= -github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= +github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28/go.mod h1:l1w+LTJZCCozeGzMEWGxRw6Mo2DfcZUvupz8HGubdes= github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= @@ -53,8 +55,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -69,8 +71,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y= -github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= From c69bd971e65f6774aaa0347df035c8f1f3f36275 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 29 Aug 2024 13:41:23 -0400 Subject: [PATCH 03/61] fix: we don't initialize the terminal when using a nilRenderer (#1120) Otherwise, a raw terminal will mess up the output. This is because a raw terminal disables termios OPOST mode which converts newlines to `\r\n` to reset the cursor to the beginning of the screen on new lines. --- tty.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tty.go b/tty.go index ed469ad43c..88aacabd51 100644 --- a/tty.go +++ b/tty.go @@ -23,6 +23,11 @@ func (p *Program) suspend() { } func (p *Program) initTerminal() error { + if _, ok := p.renderer.(*nilRenderer); ok { + // No need to initialize the terminal if we're not rendering + return nil + } + if err := p.initInput(); err != nil { return err } From a5437aced6e430fd5290009b1aa98dc14406110f Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 29 Aug 2024 15:00:51 -0400 Subject: [PATCH 04/61] feat(ci): use meta build workflow (#1123) Use charmbracelet/meta build workflow to build and test bubbletea and its examples. --- .github/workflows/build.yml | 59 +++++++++---------------------------- 1 file changed, 14 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f82f8c43a..189c3915df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,48 +3,17 @@ on: [push, pull_request] jobs: build: - strategy: - matrix: - go-version: [~1.18, ^1] - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - env: - GO111MODULE: "on" - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ${{ matrix.go-version }} - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download Go modules - run: go mod download - - - name: Build - run: | - go mod tidy - go build -v ./... - - - name: Test - run: go test ./... - - - name: Build examples - if: ${{ matrix.go-version != '~1.18' }} - run: | - go mod tidy - go build -v ./... - working-directory: ./examples - - - name: Test examples - if: ${{ matrix.go-version != '~1.18' }} - run: go test -v ./... - working-directory: ./examples - - - name: Build tutorials - if: ${{ matrix.go-version != '~1.18' }} - run: | - go mod tidy - go build -v ./... - working-directory: ./tutorials + uses: charmbracelet/meta/.github/workflows/build.yml@main + + build-go-mod: + uses: charmbracelet/meta/.github/workflows/build.yml@main + with: + go-version: "" + go-version-file: ./go.mod + + build-examples: + uses: charmbracelet/meta/.github/workflows/build.yml@main + with: + go-version: "" + go-version-file: ./examples/go.mod + working-directory: ./examples From e58efab3713e8f924e90a416e66326b23253f7ab Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 30 Aug 2024 09:20:01 -0400 Subject: [PATCH 05/61] feat: support focus-blur events (#1122) * feat: support focus-blur events This backports @caarlos0 focus-blur changes from v2-exp to v1 https://github.com/charmbracelet/bubbletea/pull/1081 Co-authored-by: Carlos Alexandro Becker * Update key_sequences.go Co-authored-by: Carlos Alexandro Becker * fix: go mod tidy --------- Co-authored-by: Carlos Alexandro Becker Co-authored-by: Christian Rocha --- examples/focus-blur/main.go | 66 +++++++++++++++++++++++ examples/go.mod | 7 +-- examples/go.sum | 16 ++---- focus.go | 9 ++++ go.mod | 7 +-- go.sum | 15 ++---- key.go | 7 +++ key_sequences.go | 12 +++++ key_test.go | 105 +++++++++++++++++++++++++----------- nil_renderer.go | 3 ++ options.go | 9 ++++ renderer.go | 9 ++++ screen.go | 20 +++++++ standard_renderer.go | 26 +++++++++ tea.go | 15 ++++++ tty.go | 4 ++ 16 files changed, 265 insertions(+), 65 deletions(-) create mode 100644 examples/focus-blur/main.go create mode 100644 focus.go diff --git a/examples/focus-blur/main.go b/examples/focus-blur/main.go new file mode 100644 index 0000000000..155ebae1f1 --- /dev/null +++ b/examples/focus-blur/main.go @@ -0,0 +1,66 @@ +package main + +// A simple program that handled losing and acquiring focus. + +import ( + "log" + + tea "github.com/charmbracelet/bubbletea" +) + +func main() { + p := tea.NewProgram(model{ + // assume we start focused... + focused: true, + reporting: true, + }, tea.WithReportFocus()) + if _, err := p.Run(); err != nil { + log.Fatal(err) + } +} + +type model struct { + focused bool + reporting bool +} + +func (m model) Init() tea.Cmd { + return nil +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.FocusMsg: + m.focused = true + case tea.BlurMsg: + m.focused = false + case tea.KeyMsg: + switch msg.String() { + case "t": + m.reporting = !m.reporting + case "ctrl+c", "q": + return m, tea.Quit + } + } + + return m, nil +} + +func (m model) View() string { + s := "Hi. Focus report is currently " + if m.reporting { + s += "enabled" + } else { + s += "disabled" + } + s += ".\n\n" + + if m.reporting { + if m.focused { + s += "This program is currently focused!" + } else { + s += "This program is currently blurred!" + } + } + return s + "\n\nTo quit sooner press ctrl-c, or t to toggle focus reporting...\n" +} diff --git a/examples/go.mod b/examples/go.mod index af11894936..cde0c65c7b 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,11 +22,9 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect - github.com/charmbracelet/x/input v0.1.0 // indirect - github.com/charmbracelet/x/term v0.1.1 // indirect - github.com/charmbracelet/x/windows v0.1.0 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect @@ -40,7 +38,6 @@ require ( github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect golang.org/x/net v0.27.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index f75c3fb423..b3d7fa67d2 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,18 +22,14 @@ github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28/go.mod h1:l1w+LTJZCCozeGzMEWGxRw6Mo2DfcZUvupz8HGubdes= -github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= -github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= -github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= -github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= -github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4= -github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -73,15 +69,11 @@ 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= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4= github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= -golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= -golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= diff --git a/focus.go b/focus.go new file mode 100644 index 0000000000..4d34bea6f8 --- /dev/null +++ b/focus.go @@ -0,0 +1,9 @@ +package tea + +// FocusMsg represents a terminal focus message. +// This occurs when the terminal gains focus. +type FocusMsg struct{} + +// BlurMsg represents a terminal blur message. +// This occurs when the terminal loses focus. +type BlurMsg struct{} diff --git a/go.mod b/go.mod index b03c969c12..cfe3556678 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.13.0 - github.com/charmbracelet/x/ansi v0.1.4 - github.com/charmbracelet/x/term v0.1.1 + github.com/charmbracelet/x/ansi v0.2.3 + github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 @@ -16,13 +16,10 @@ require ( require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/x/input v0.1.0 // indirect - github.com/charmbracelet/x/windows v0.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/text v0.3.8 // indirect ) diff --git a/go.sum b/go.sum index e027dcf56c..890268a9b3 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,10 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= -github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= -github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= -github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= -github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4= -github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -29,9 +25,6 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/key.go b/key.go index 89a588aec0..ab4792ac63 100644 --- a/key.go +++ b/key.go @@ -628,6 +628,13 @@ func detectOneMsg(b []byte, canHaveMoreData bool) (w int, msg Msg) { } } + // Detect focus events. + var foundRF bool + foundRF, w, msg = detectReportFocus(b) + if foundRF { + return w, msg + } + // Detect bracketed paste. var foundbp bool foundbp, w, msg = detectBracketedPaste(b) diff --git a/key_sequences.go b/key_sequences.go index 4ba0f79e34..15483ef528 100644 --- a/key_sequences.go +++ b/key_sequences.go @@ -117,3 +117,15 @@ func detectBracketedPaste(input []byte) (hasBp bool, width int, msg Msg) { return true, inputLen, KeyMsg(k) } + +// detectReportFocus detects a focus report sequence. +// nolint: gomnd +func detectReportFocus(input []byte) (hasRF bool, width int, msg Msg) { + switch { + case bytes.Equal(input, []byte("\x1b[I")): + return true, 3, FocusMsg{} + case bytes.Equal(input, []byte("\x1b[O")): + return true, 3, BlurMsg{} + } + return false, 0, nil +} diff --git a/key_test.go b/key_test.go index 67b0c50ed5..0970b986f2 100644 --- a/key_test.go +++ b/key_test.go @@ -134,6 +134,15 @@ func TestDetectOneMsg(t *testing.T) { // Add tests for the inputs that detectOneMsg() can parse, but // detectSequence() cannot. td = append(td, + // focus/blur + seqTest{ + []byte{'\x1b', '[', 'I'}, + FocusMsg{}, + }, + seqTest{ + []byte{'\x1b', '[', 'O'}, + BlurMsg{}, + }, // Mouse event. seqTest{ []byte{'\x1b', '[', 'M', byte(32) + 0b0100_0000, byte(65), byte(49)}, @@ -242,7 +251,8 @@ func TestReadInput(t *testing.T) { out []Msg } testData := []test{ - {"a", + { + "a", []byte{'a'}, []Msg{ KeyMsg{ @@ -251,7 +261,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {" ", + { + " ", []byte{' '}, []Msg{ KeyMsg{ @@ -260,14 +271,16 @@ func TestReadInput(t *testing.T) { }, }, }, - {"a alt+a", + { + "a alt+a", []byte{'a', '\x1b', 'a'}, []Msg{ KeyMsg{Type: KeyRunes, Runes: []rune{'a'}}, KeyMsg{Type: KeyRunes, Runes: []rune{'a'}, Alt: true}, }, }, - {"a alt+a a", + { + "a alt+a a", []byte{'a', '\x1b', 'a', 'a'}, []Msg{ KeyMsg{Type: KeyRunes, Runes: []rune{'a'}}, @@ -275,7 +288,8 @@ func TestReadInput(t *testing.T) { KeyMsg{Type: KeyRunes, Runes: []rune{'a'}}, }, }, - {"ctrl+a", + { + "ctrl+a", []byte{byte(keySOH)}, []Msg{ KeyMsg{ @@ -283,14 +297,16 @@ func TestReadInput(t *testing.T) { }, }, }, - {"ctrl+a ctrl+b", + { + "ctrl+a ctrl+b", []byte{byte(keySOH), byte(keySTX)}, []Msg{ KeyMsg{Type: KeyCtrlA}, KeyMsg{Type: KeyCtrlB}, }, }, - {"alt+a", + { + "alt+a", []byte{byte(0x1b), 'a'}, []Msg{ KeyMsg{ @@ -300,7 +316,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"abcd", + { + "abcd", []byte{'a', 'b', 'c', 'd'}, []Msg{ KeyMsg{ @@ -309,7 +326,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"up", + { + "up", []byte("\x1b[A"), []Msg{ KeyMsg{ @@ -317,7 +335,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"wheel up", + { + "wheel up", []byte{'\x1b', '[', 'M', byte(32) + 0b0100_0000, byte(65), byte(49)}, []Msg{ MouseMsg{ @@ -329,7 +348,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"left motion release", + { + "left motion release", []byte{ '\x1b', '[', 'M', byte(32) + 0b0010_0000, byte(32 + 33), byte(16 + 33), '\x1b', '[', 'M', byte(32) + 0b0000_0011, byte(64 + 33), byte(32 + 33), @@ -351,7 +371,8 @@ func TestReadInput(t *testing.T) { }), }, }, - {"shift+tab", + { + "shift+tab", []byte{'\x1b', '[', 'Z'}, []Msg{ KeyMsg{ @@ -359,11 +380,13 @@ func TestReadInput(t *testing.T) { }, }, }, - {"enter", + { + "enter", []byte{'\r'}, []Msg{KeyMsg{Type: KeyEnter}}, }, - {"alt+enter", + { + "alt+enter", []byte{'\x1b', '\r'}, []Msg{ KeyMsg{ @@ -372,7 +395,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"insert", + { + "insert", []byte{'\x1b', '[', '2', '~'}, []Msg{ KeyMsg{ @@ -380,7 +404,8 @@ func TestReadInput(t *testing.T) { }, }, }, - {"alt+ctrl+a", + { + "alt+ctrl+a", []byte{'\x1b', byte(keySOH)}, []Msg{ KeyMsg{ @@ -389,52 +414,64 @@ func TestReadInput(t *testing.T) { }, }, }, - {"?CSI[45 45 45 45 88]?", + { + "?CSI[45 45 45 45 88]?", []byte{'\x1b', '[', '-', '-', '-', '-', 'X'}, []Msg{unknownCSISequenceMsg([]byte{'\x1b', '[', '-', '-', '-', '-', 'X'})}, }, // Powershell sequences. - {"up", + { + "up", []byte{'\x1b', 'O', 'A'}, []Msg{KeyMsg{Type: KeyUp}}, }, - {"down", + { + "down", []byte{'\x1b', 'O', 'B'}, []Msg{KeyMsg{Type: KeyDown}}, }, - {"right", + { + "right", []byte{'\x1b', 'O', 'C'}, []Msg{KeyMsg{Type: KeyRight}}, }, - {"left", + { + "left", []byte{'\x1b', 'O', 'D'}, []Msg{KeyMsg{Type: KeyLeft}}, }, - {"alt+enter", + { + "alt+enter", []byte{'\x1b', '\x0d'}, []Msg{KeyMsg{Type: KeyEnter, Alt: true}}, }, - {"alt+backspace", + { + "alt+backspace", []byte{'\x1b', '\x7f'}, []Msg{KeyMsg{Type: KeyBackspace, Alt: true}}, }, - {"ctrl+@", + { + "ctrl+@", []byte{'\x00'}, []Msg{KeyMsg{Type: KeyCtrlAt}}, }, - {"alt+ctrl+@", + { + "alt+ctrl+@", []byte{'\x1b', '\x00'}, []Msg{KeyMsg{Type: KeyCtrlAt, Alt: true}}, }, - {"esc", + { + "esc", []byte{'\x1b'}, []Msg{KeyMsg{Type: KeyEsc}}, }, - {"alt+esc", + { + "alt+esc", []byte{'\x1b', '\x1b'}, []Msg{KeyMsg{Type: KeyEsc, Alt: true}}, }, - {"[a b] o", + { + "[a b] o", []byte{ '\x1b', '[', '2', '0', '0', '~', 'a', ' ', 'b', @@ -446,11 +483,13 @@ func TestReadInput(t *testing.T) { KeyMsg{Type: KeyRunes, Runes: []rune("o")}, }, }, - {"[a\x03\nb]", + { + "[a\x03\nb]", []byte{ '\x1b', '[', '2', '0', '0', '~', 'a', '\x03', '\n', 'b', - '\x1b', '[', '2', '0', '1', '~'}, + '\x1b', '[', '2', '0', '1', '~', + }, []Msg{ KeyMsg{Type: KeyRunes, Runes: []rune("a\x03\nb"), Paste: true}, }, @@ -460,11 +499,13 @@ func TestReadInput(t *testing.T) { // Sadly, utf8.DecodeRune([]byte(0xfe)) returns a valid rune on windows. // This is incorrect, but it makes our test fail if we try it out. testData = append(testData, - test{"?0xfe?", + test{ + "?0xfe?", []byte{'\xfe'}, []Msg{unknownInputByteMsg(0xfe)}, }, - test{"a ?0xfe? b", + test{ + "a ?0xfe? b", []byte{'a', '\xfe', ' ', 'b'}, []Msg{ KeyMsg{Type: KeyRunes, Runes: []rune{'a'}}, diff --git a/nil_renderer.go b/nil_renderer.go index f4a83b6bc4..0bc4a17206 100644 --- a/nil_renderer.go +++ b/nil_renderer.go @@ -23,3 +23,6 @@ func (n nilRenderer) enableMouseSGRMode() {} func (n nilRenderer) disableMouseSGRMode() {} func (n nilRenderer) bracketedPasteActive() bool { return false } func (n nilRenderer) setWindowTitle(_ string) {} +func (n nilRenderer) reportFocus() bool { return false } +func (n nilRenderer) enableReportFocus() {} +func (n nilRenderer) disableReportFocus() {} diff --git a/options.go b/options.go index a810fe1c7b..4a56fc8114 100644 --- a/options.go +++ b/options.go @@ -234,3 +234,12 @@ func WithFPS(fps int) ProgramOption { p.fps = fps } } + +// WithReportFocus enables reporting when the terminal gains and lost focus. +// +// You can then check for FocusMsg and BlurMsg in your model's Update method. +func WithReportFocus() ProgramOption { + return func(p *Program) { + p.startupOptions |= withReportFocus + } +} diff --git a/renderer.go b/renderer.go index de3936e73b..9eb7943bcf 100644 --- a/renderer.go +++ b/renderer.go @@ -70,6 +70,15 @@ type renderer interface { // setWindowTitle sets the terminal window title. setWindowTitle(string) + + // reportFocus returns whether reporting focus events is enabled. + reportFocus() bool + + // enableReportFocus reports focus events to the program. + enableReportFocus() + + // disableReportFocus stops reporting focus events to the program. + disableReportFocus() } // repaintMsg forces a full repaint. diff --git a/screen.go b/screen.go index 6256c15920..dfec48f0b4 100644 --- a/screen.go +++ b/screen.go @@ -144,6 +144,26 @@ func DisableBracketedPaste() Msg { // disableBracketedPasteMsg with DisableBracketedPaste. type disableBracketedPasteMsg struct{} +// enableReportFocusMsg is an internal message that signals to enable focus +// reporting. You can send an enableReportFocusMsg with EnableReportFocus. +type enableReportFocusMsg struct{} + +// EnableReportFocus is a special command that tells the Bubble Tea program to +// report focus events to the program. +func EnableReportFocus() Msg { + return enableReportFocusMsg{} +} + +// disableReportFocusMsg is an internal message that signals to disable focus +// reporting. You can send an disableReportFocusMsg with DisableReportFocus. +type disableReportFocusMsg struct{} + +// DisableReportFocus is a special command that tells the Bubble Tea program to +// stop reporting focus events to the program. +func DisableReportFocus() Msg { + return disableReportFocusMsg{} +} + // EnterAltScreen enters the alternate screen buffer, which consumes the entire // terminal window. ExitAltScreen will return the terminal to its former state. // diff --git a/standard_renderer.go b/standard_renderer.go index f81920de01..59448e1d41 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -47,6 +47,9 @@ type standardRenderer struct { // whether or not we're currently using bracketed paste bpActive bool + // reportingFocus whether reporting focus events is enabled + reportingFocus bool + // renderer dimensions; usually the size of the window width int height int @@ -458,6 +461,29 @@ func (r *standardRenderer) bracketedPasteActive() bool { return r.bpActive } +func (r *standardRenderer) enableReportFocus() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.EnableReportFocus) + r.reportingFocus = true +} + +func (r *standardRenderer) disableReportFocus() { + r.mtx.Lock() + defer r.mtx.Unlock() + + r.execute(ansi.DisableReportFocus) + r.reportingFocus = false +} + +func (r *standardRenderer) reportFocus() bool { + r.mtx.Lock() + defer r.mtx.Unlock() + + return r.reportingFocus +} + // setWindowTitle sets the terminal window title. func (r *standardRenderer) setWindowTitle(title string) { r.execute(ansi.SetWindowTitle(title)) diff --git a/tea.go b/tea.go index 62cd6415bb..5ed9707622 100644 --- a/tea.go +++ b/tea.go @@ -97,6 +97,7 @@ const ( // feature is on by default. withoutCatchPanics withoutBracketedPaste + withReportFocus ) // channelHandlers manages the series of channels returned by various processes. @@ -167,6 +168,7 @@ type Program struct { ignoreSignals uint32 bpWasActive bool // was the bracketed paste mode active before releasing the terminal? + reportFocus bool // was focus reporting active before releasing the terminal? filter func(Model, Msg) Msg @@ -390,6 +392,12 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { case disableBracketedPasteMsg: p.renderer.disableBracketedPaste() + case enableReportFocusMsg: + p.renderer.enableReportFocus() + + case disableReportFocusMsg: + p.renderer.disableReportFocus() + case execMsg: // NB: this blocks. p.exec(msg.cmd, msg.fn) @@ -542,6 +550,9 @@ func (p *Program) Run() (Model, error) { p.renderer.enableMouseAllMotion() p.renderer.enableMouseSGRMode() } + if p.startupOptions&withReportFocus != 0 { + p.renderer.enableReportFocus() + } // Start the renderer. p.renderer.start() @@ -694,6 +705,7 @@ func (p *Program) ReleaseTerminal() error { p.renderer.stop() p.altScreenWasActive = p.renderer.altScreen() p.bpWasActive = p.renderer.bracketedPasteActive() + p.reportFocus = p.renderer.reportFocus() } return p.restoreTerminalState() @@ -723,6 +735,9 @@ func (p *Program) RestoreTerminal() error { if p.bpWasActive { p.renderer.enableBracketedPaste() } + if p.reportFocus { + p.renderer.enableReportFocus() + } // If the output is a terminal, it may have been resized while another // process was at the foreground, in which case we may not have received diff --git a/tty.go b/tty.go index 88aacabd51..02507782cc 100644 --- a/tty.go +++ b/tty.go @@ -44,6 +44,10 @@ func (p *Program) restoreTerminalState() error { p.renderer.showCursor() p.disableMouse() + if p.renderer.reportFocus() { + p.renderer.disableReportFocus() + } + if p.renderer.altScreen() { p.renderer.exitAltScreen() From d5f1b715f3314b57e140589bc0d7a9f1be129cec Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Fri, 30 Aug 2024 10:18:07 -0400 Subject: [PATCH 06/61] docs(focus): add some GoDoc links and add note on focus support --- options.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/options.go b/options.go index 4a56fc8114..06abf4a983 100644 --- a/options.go +++ b/options.go @@ -235,9 +235,13 @@ func WithFPS(fps int) ProgramOption { } } -// WithReportFocus enables reporting when the terminal gains and lost focus. +// WithReportFocus enables reporting when the terminal gains and loses +// focus. When this is enabled [FocusMsg] and [BlurMsg] messages will be sent +// to your Update method. // -// You can then check for FocusMsg and BlurMsg in your model's Update method. +// Note that while most terminals and multiplexers support focus reporting, +// some do not. Also note that tmux needs to be configured to report focus +// events. func WithReportFocus() ProgramOption { return func(p *Program) { p.startupOptions |= withReportFocus From 6d43c27f66070575921f4fc0af025facdf037bca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:34:17 -0300 Subject: [PATCH 07/61] chore(deps): bump github.com/charmbracelet/bubbles in /examples (#1131) Bumps [github.com/charmbracelet/bubbles](https://github.com/charmbracelet/bubbles) from 0.19.0 to 0.20.0. - [Release notes](https://github.com/charmbracelet/bubbles/releases) - [Changelog](https://github.com/charmbracelet/bubbles/blob/master/.goreleaser.yml) - [Commits](https://github.com/charmbracelet/bubbles/compare/v0.19.0...v0.20.0) --- updated-dependencies: - dependency-name: github.com/charmbracelet/bubbles dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/go.mod | 4 ++-- examples/go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index cde0c65c7b..3a2c31e0cf 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -5,8 +5,8 @@ go 1.21 toolchain go1.22.5 require ( - github.com/charmbracelet/bubbles v0.19.0 - github.com/charmbracelet/bubbletea v0.27.0 + github.com/charmbracelet/bubbles v0.20.0 + github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/harmonica v0.2.0 github.com/charmbracelet/lipgloss v0.13.0 diff --git a/examples/go.sum b/examples/go.sum index b3d7fa67d2..b9b648f1ae 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -14,8 +14,8 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/charmbracelet/bubbles v0.19.0 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0= -github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= From 7ca1b0b5ca53a638ac09b628cead1d238ba71ea1 Mon Sep 17 00:00:00 2001 From: bashbunni <15822994+bashbunni@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:58:00 -0700 Subject: [PATCH 08/61] docs(featured): clean up in the wild list (#1130) * docs(featured): clean up in the wild list * docs(readme): auto-format * docs(readme): organize in-the-wild a li'l more * docs: clarify where to submit a PR (charm and friends) --------- Co-authored-by: Christian Rocha --- README.md | 168 +++++++++++++++++------------------------------------- 1 file changed, 52 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 9a8d93e2a2..f80e04ea21 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Be sure to check out [Bubbles][bubbles], a library of common UI components for B Text Input Example from Bubbles

-*** +--- ## Tutorial @@ -49,7 +49,7 @@ By the way, the non-annotated source code for this program is available [on GitHub][tut-source]. [elm]: https://guide.elm-lang.org/architecture/ -[tut-source]:https://github.com/charmbracelet/bubbletea/tree/master/tutorials/basics +[tut-source]: https://github.com/charmbracelet/bubbletea/tree/master/tutorials/basics ### Enough! Let's get to it. @@ -72,9 +72,9 @@ import ( Bubble Tea programs are comprised of a **model** that describes the application state and three simple methods on that model: -* **Init**, a function that returns an initial command for the application to run. -* **Update**, a function that handles incoming events and updates the model accordingly. -* **View**, a function that renders the UI based on the data in the model. +- **Init**, a function that returns an initial command for the application to run. +- **Update**, a function that handles incoming events and updates the model accordingly. +- **View**, a function that renders the UI based on the data in the model. ### The Model @@ -275,11 +275,11 @@ $ dlv connect 127.0.0.1:43000 ``` If you do not explicitly supply the `--listen` flag, the port used will vary -per run, so passing this in makes the debugger easier to use from a script -or your IDE of choice. +per run, so passing this in makes the debugger easier to use from a script +or your IDE of choice. -Additionally, we pass in `--api-version=2` because delve defaults to version 1 -for backwards compatibility reasons. However, delve recommends using version 2 +Additionally, we pass in `--api-version=2` because delve defaults to version 1 +for backwards compatibility reasons. However, delve recommends using version 2 for all new development and some clients may no longer work with version 1. For more information, see the [Delve documentation](https://github.com/go-delve/delve/tree/master/Documentation/api). @@ -305,13 +305,13 @@ your program in another window. ## Libraries we use with Bubble Tea -* [Bubbles][bubbles]: Common Bubble Tea components such as text inputs, viewports, spinners and so on -* [Lip Gloss][lipgloss]: Style, format and layout tools for terminal applications -* [Harmonica][harmonica]: A spring animation library for smooth, natural motion -* [BubbleZone][bubblezone]: Easy mouse event tracking for Bubble Tea components -* [ntcharts][ntcharts]: A terminal charting library built for Bubble Tea and [Lip Gloss][lipgloss] -* [Termenv][termenv]: Advanced ANSI styling for terminal applications -* [Reflow][reflow]: Advanced ANSI-aware methods for working with text +- [Bubbles][bubbles]: Common Bubble Tea components such as text inputs, viewports, spinners and so on +- [Lip Gloss][lipgloss]: Style, format and layout tools for terminal applications +- [Harmonica][harmonica]: A spring animation library for smooth, natural motion +- [BubbleZone][bubblezone]: Easy mouse event tracking for Bubble Tea components +- [ntcharts][ntcharts]: A terminal charting library built for Bubble Tea and [Lip Gloss][lipgloss] +- [Termenv][termenv]: Advanced ANSI styling for terminal applications +- [Reflow][reflow]: Advanced ANSI-aware methods for working with text [bubbles]: https://github.com/charmbracelet/bubbles [lipgloss]: https://github.com/charmbracelet/lipgloss @@ -323,109 +323,44 @@ your program in another window. ## Bubble Tea in the Wild -For some Bubble Tea programs in production, see: - -* [ASCII Movie](https://github.com/gabe565/ascii-movie): a Star Wars ASCII art movie player -* [AT CLI](https://github.com/daskycodes/at_cli): execute AT Commands via serial port connections -* [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform -* [brows](https://github.com/rubysolo/brows): a GitHub release browser -* [Canard](https://github.com/mrusme/canard): an RSS client -* [charm](https://github.com/charmbracelet/charm): the official Charm user account manager -* [chatgpt-cli](https://github.com/j178/chatgpt): a CLI for ChatGPT -* [chatgpt-tui](https://github.com/tearingItUp786/chatgpt-tui): a TUI for ChatGPT with SQLite sessions -* [ChatGPTUI](https://github.com/dwisiswant0/chatgptui): a TUI for ChatGPT -* [chezmoi](https://github.com/twpayne/chezmoi): securely manage your dotfiles across multiple machines -* [chip-8](https://github.com/braheezy/chip-8): a CHIP-8 interpreter -* [chtop](https://github.com/chhetripradeep/chtop): monitor your ClickHouse node without leaving the terminal -* [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in the terminal -* [clidle](https://github.com/ajeetdsouza/clidle): a Wordle clone -* [cLive](https://github.com/koki-develop/clive): automate terminal operations and view them live in a browser -* [container-canary](https://github.com/NVIDIA/container-canary): a container validator -* [countdown](https://github.com/aldernero/countdown): a multi-event countdown timer -* [CRT](https://github.com/BigJk/crt): a simple terminal emulator for running Bubble Tea in a dedicated window, with optional shaders -* [cueitup](https://github.com/dhth/cueitup): inspect messages in an AWS SQS queue in a simple and deliberate manner -* [Daytona](https://github.com/daytonaio/daytona): an development environment manager -* [dns53](https://github.com/purpleclay/dns53): dynamic DNS with Amazon Route53; expose your EC2 quickly, securely and privately -* [eks-node-viewer](https://github.com/awslabs/eks-node-viewer): a tool for visualizing dynamic node usage within an EKS cluster -* [End Of Eden](https://github.com/BigJk/end_of_eden): a "Slay the Spire"-like, roguelike deck-builder game -* [enola](https://github.com/sherlock-project/enola): find social media accounts by username across social networks -* [flapioca](https://github.com/kbrgl/flapioca): Flappy Bird on the CLI! -* [fm](https://github.com/knipferrc/fm): a terminal-based file manager -* [fork-cleaner](https://github.com/caarlos0/fork-cleaner): clean up old and inactive forks in your GitHub account -* [fractals-cli](https://github.com/MicheleFiladelfia/fractals-cli): a multiplatform terminal fractal explorer -* [fztea](https://github.com/jon4hz/fztea): a Flipper Zero TUI -* [gama](https://github.com/termkit/gama): manage GitHub Actions from the terminal -* [gambit](https://github.com/maaslalani/gambit): chess in the terminal -* [gembro](https://git.sr.ht/~rafael/gembro): a mouse-driven Gemini browser -* [gh-b](https://github.com/joaom00/gh-b): a GitHub CLI extension for managing branches -* [gh-dash](https://www.github.com/dlvhdr/gh-dash): a GitHub CLI extension for PRs and issues -* [gitflow-toolkit](https://github.com/mritd/gitflow-toolkit): a GitFlow submission tool -* [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser, and online markdown stash -* [go-sweep](https://github.com/maxpaulus43/go-sweep): Minesweeper in the terminal -* [gocovsh](https://github.com/orlangure/gocovsh): explore Go coverage reports from the CLI -* [got](https://github.com/fedeztk/got): a simple translator and text-to-speech app built on simplytranslate's APIs -* [gum](https://github.com/charmbracelet/gum): interactivity and styling for shells and shell scripts -* [hiSHtory](https://github.com/ddworken/hishtory): your shell history in context: synced, and queryable -* [httpit](https://github.com/gonetx/httpit): a rapid http(s) benchmark tool -* [Huh?](https://github.com/charmbracelet/huh): an interactive prompt and form toolkit -* [IDNT](https://github.com/r-darwish/idnt): a batch software uninstaller -* [json-log-viewer](https://github.com/hedhyw/json-log-viewer): an interactive JSON log viewer -* [kboard](https://github.com/CamiloGarciaLaRotta/kboard): a typing game -* [kplay](https://github.com/dhth/kplay): inspect messages in a Kafka topic -* [laboon](https://github.com/arisnacg/laboon): a Docker-desktop-style container manager -* [mc](https://github.com/minio/mc): the official [MinIO](https://min.io) client -* [mergestat](https://github.com/mergestat/mergestat): run SQL queries on git repositories -* [meteor](https://github.com/stefanlogue/meteor): a highly customizable conventional commit message tool -* [mods](https://github.com/charmbracelet/mods): AI on the CLI, built for pipelines -* [nachrichten](https://github.com/zMoooooritz/nachrichten): access up-to-date news in German provided by the [Tagesschau](https://www.tagesschau.de/) -* [Neon Modem Overdrive](https://github.com/mrusme/neonmodem): a BBS-style TUI client for Discourse, Lemmy, Lobste.rs and Hacker News -* [nom](https://github.com/guyfedwards/nom): an RSS reader and manager -* [Noted](https://github.com/torbratsberg/noted): a note viewer and manager -* [outtasync](https://github.com/dhth/outtasync): identify CloudFormation stacks that are out of sync with their template files -* [pathos](https://github.com/chip/pathos): a PATH environment variable editor -* [Plandex](https://github.com/plandex-ai/plandex): a terminal-based AI coding engine for complex tasks -* [portal](https://github.com/ZinoKader/portal): secure transfers between computers -* [prs](https://github.com/dhth/prs): stay up to date with your PRs -* [puffin](https://github.com/siddhantac/puffin): a TUI for hledger to manage your finances -* [pug](https://github.com/leg100/pug): terraform task manager -* [punchout](https://github.com/dhth/punchout): takes the suck out of logging time on JIRA -* [redis-viewer](https://github.com/SaltFishPr/redis-viewer): a Redis database browser -* [redis_tui](https://github.com/mat2cc/redis_tui): a Redis database browser -* [schemas](https://github.com/dhth/schemas): lets you inspect postgres schemas in the terminal -* [scrabbler](https://github.com/wI2L/scrabbler): an automatic draw tool for your duplicate Scrabble games -* [sku](https://github.com/fedeztk/sku): Sudoku on the CLI -* [Slides](https://github.com/maaslalani/slides): a markdown-based presentation tool -* [SlurmCommander](https://github.com/CLIP-HPC/SlurmCommander): a Slurm workload manager -* [Soft Serve](https://github.com/charmbracelet/soft-serve): a command-line-first Git server that runs a TUI over SSH -* [solitaire-tui](https://github.com/brianstrauch/solitaire-tui): Klondike Solitaire for the terminal -* [StormForge Optimize Controller](https://github.com/thestormforge/optimize-controller): a tool for experimenting with application configurations in Kubernetes -* [Storydb](https://github.com/grrlopes/storydb): an improved bash/zsh-style ctrl+r command history finder -* [STTG](https://github.com/wille1101/sttg): a teletext client for SVT, Sweden’s national public television station -* [sttr](https://github.com/abhimanyu003/sttr): a general-purpose text transformer -* [superfile](https://github.com/MHNightCat/superfile) a fancy, modern terminal-based file manager -* [tasktimer](https://github.com/caarlos0/tasktimer): a dead-simple task timer -* [termdbms](https://github.com/mathaou/termdbms): a keyboard and mouse driven database browser -* [tgpt](https://github.com/aandrew-me/tgpt): conversational AI for the CLI; no API keys necessary -* [ticker](https://github.com/achannarasappa/ticker): a terminal stock viewer and stock position tracker -* [trainer](https://github.com/rusinikita/trainer): a Go concurrency coding interview simulator with learning materials -* [tran](https://github.com/abdfnx/tran): securely transfer stuff between computers (based on [portal](https://github.com/ZinoKader/portal)) -* [Trufflehog](https://github.com/trufflesecurity/trufflehog): find leaked credentials -* [Typer](https://github.com/maaslalani/typer): a typing test -* [typioca](https://github.com/bloznelis/typioca): a typing test -* [tz](https://github.com/oz/tz): a scheduling aid for people in multiple time zones -* [ugm](https://github.com/ariasmn/ugm): a unix user and group browser -* [walk](https://github.com/antonmedv/walk): a terminal navigator -* [wander](https://github.com/robinovitch61/wander): a HashiCorp Nomad terminal client -* [WG Commander](https://github.com/AndrianBdn/wg-cmd): a TUI for a simple WireGuard VPN setup -* [wishlist](https://github.com/charmbracelet/wishlist): an SSH directory +There are over 8k applications built with Bubble Tea! Here are a handful of ’em. + +### Staff favourites + +- [chezmoi](https://github.com/twpayne/chezmoi): securely manage your dotfiles across multiple machines +- [circumflex](https://github.com/bensadeh/circumflex): read Hacker News in the terminal +- [gh-dash](https://www.github.com/dlvhdr/gh-dash): a GitHub CLI extension for PRs and issues +- [Tetrigo](https://github.com/Broderick-Westrope/tetrigo): Tetris in the terminal + +### In Industry + +- Microsoft Azure – [Aztify](https://github.com/Azure/aztfy): bring Microsoft Azure resources under Terraform +- Daytona – [Daytona](https://github.com/daytonaio/daytona): open source dev environment manager +- Truffle Security Co. – [Trufflehog](https://github.com/trufflesecurity/trufflehog): find leaked credentials +- NVIDIA – [container-canary](https://github.com/NVIDIA/container-canary) from NVIDIA: a container validator +- AWS – [eks-node-viewer](https://github.com/awslabs/eks-node-viewer) from AWS: a tool for visualizing dynamic node usage within an EKS cluster +- MinIO – [mc](https://github.com/minio/mc) from Min.io: the official [MinIO](https://min.io) client + +### Charm stuff + +- [Glow](https://github.com/charmbracelet/glow): a markdown reader, browser, and online markdown stash +- [Huh?](https://github.com/charmbracelet/huh): an interactive prompt and form toolkit +- [Mods](https://github.com/charmbracelet/mods): AI on the CLI, built for pipelines +- [Wishlist](https://github.com/charmbracelet/wishlist): an SSH directory (and bastion!) + +### There’s so much more where that came from + +For more applications built with Bubble Tea see [Charm & Friends][community]. +Is there something cool you made with Bubble Tea you want to share? [PRs][community] are +welcome! ## Feedback -We'd love to hear your thoughts on this project. Feel free to drop us a note! +We’d love to hear your thoughts on this project. Feel free to drop us a note! -* [Twitter](https://twitter.com/charmcli) -* [The Fediverse](https://mastodon.social/@charmcli) -* [Discord](https://charm.sh/chat) +- [Twitter](https://twitter.com/charmcli) +- [The Fediverse](https://mastodon.social/@charmcli) +- [Discord](https://charm.sh/chat) ## Acknowledgments @@ -437,12 +372,13 @@ of days past. [elm]: https://guide.elm-lang.org/architecture/ [gotea]: https://github.com/tj/go-tea [zb]: https://de.wikipedia.org/wiki/Zeichenorientierte_Benutzerschnittstelle +[community]: https://github.com/charm-and-friends/charm-in-the-wild ## License [MIT](https://github.com/charmbracelet/bubbletea/raw/master/LICENSE) -*** +--- Part of [Charm](https://charm.sh). From 0589921d2e5a1ee33e0dba1d54836946e78fe059 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 10 Sep 2024 16:05:51 -0400 Subject: [PATCH 09/61] fix: recover from panics within cmds We should recover from panics within a cmd. Currently, Bubble Tea only recovers from panics within the eventLoop. This makes it so that it also recovers from panics within cmd go routines. Supersedes: https://github.com/charmbracelet/bubbletea/pull/846 Fixes: https://github.com/charmbracelet/bubbletea/issues/234 --- tea.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tea.go b/tea.go index 5ed9707622..e7865a8ec5 100644 --- a/tea.go +++ b/tea.go @@ -312,6 +312,11 @@ func (p *Program) handleCommands(cmds chan Cmd) chan struct{} { // possible to cancel them so we'll have to leak the goroutine // until Cmd returns. go func() { + // Recover from panics. + if !p.startupOptions.has(withoutCatchPanics) { + defer p.recoverFromPanic() + } + msg := cmd() // this can be long. p.Send(msg) }() @@ -512,14 +517,7 @@ func (p *Program) Run() (Model, error) { // Recover from panics. if !p.startupOptions.has(withoutCatchPanics) { - defer func() { - if r := recover(); r != nil { - p.shutdown(true) - fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r) - debug.PrintStack() - return - } - }() + defer p.recoverFromPanic() } // If no renderer is set use the standard one. @@ -691,6 +689,16 @@ func (p *Program) shutdown(kill bool) { p.finished <- struct{}{} } +// recoverFromPanic recovers from a panic, prints the stack trace, and restores +// the terminal to a usable state. +func (p *Program) recoverFromPanic() { + if r := recover(); r != nil { + p.shutdown(true) + fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r) + debug.PrintStack() + } +} + // ReleaseTerminal restores the original terminal state and cancels the input // reader. You can return control to the Program with RestoreTerminal. func (p *Program) ReleaseTerminal() error { From 6e71f52a8add0fdeba202d4e1bdd289182b156ac Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 11 Sep 2024 11:57:21 -0400 Subject: [PATCH 10/61] fix: restore the terminal on kill Supersedes: https://github.com/charmbracelet/bubbletea/pull/1133 Fixes: https://github.com/charmbracelet/bubbletea/issues/1127 --- tea.go | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/tea.go b/tea.go index e7865a8ec5..87211ba299 100644 --- a/tea.go +++ b/tea.go @@ -128,6 +128,10 @@ func (h channelHandlers) shutdown() { type Program struct { initialModel Model + // handlers is a list of channels that need to be waited on before the + // program can exit. + handlers channelHandlers + // Configuration options that will set as the program is initializing, // treated as bits. These options can be set via various ProgramOptions. startupOptions startupOptions @@ -465,7 +469,7 @@ func (p *Program) eventLoop(model Model, cmds chan Cmd) (Model, error) { // terminated by either [Program.Quit], [Program.Kill], or its signal handler. // Returns the final model. func (p *Program) Run() (Model, error) { - handlers := channelHandlers{} + p.handlers = channelHandlers{} cmds := make(chan Cmd) p.errs = make(chan error) p.finished = make(chan struct{}, 1) @@ -512,7 +516,7 @@ func (p *Program) Run() (Model, error) { // Handle signals. if !p.startupOptions.has(withoutSignalHandler) { - handlers.add(p.handleSignals()) + p.handlers.add(p.handleSignals()) } // Recover from panics. @@ -559,7 +563,7 @@ func (p *Program) Run() (Model, error) { model := p.initialModel if initCmd := model.Init(); initCmd != nil { ch := make(chan struct{}) - handlers.add(ch) + p.handlers.add(ch) go func() { defer close(ch) @@ -582,10 +586,10 @@ func (p *Program) Run() (Model, error) { } // Handle resize events. - handlers.add(p.handleResize()) + p.handlers.add(p.handleResize()) // Process commands. - handlers.add(p.handleCommands(cmds)) + p.handlers.add(p.handleCommands(cmds)) // Run event loop, handle updates and draw. model, err := p.eventLoop(model, cmds) @@ -597,21 +601,6 @@ func (p *Program) Run() (Model, error) { p.renderer.write(model.View()) } - // Tear down. - p.cancel() - - // Check if the cancel reader has been setup before waiting and closing. - if p.cancelReader != nil { - // Wait for input loop to finish. - if p.cancelReader.Cancel() { - p.waitForReadLoop() - } - _ = p.cancelReader.Close() - } - - // Wait for all handlers to finish. - handlers.shutdown() - // Restore terminal state. p.shutdown(killed) @@ -666,7 +655,7 @@ func (p *Program) Quit() { // The final render that you would normally see when quitting will be skipped. // [program.Run] returns a [ErrProgramKilled] error. func (p *Program) Kill() { - p.cancel() + p.shutdown(true) } // Wait waits/blocks until the underlying Program finished shutting down. @@ -677,6 +666,22 @@ func (p *Program) Wait() { // shutdown performs operations to free up resources and restore the terminal // to its original state. func (p *Program) shutdown(kill bool) { + p.cancel() + + // Wait for all handlers to finish. + p.handlers.shutdown() + + // Check if the cancel reader has been setup before waiting and closing. + if p.cancelReader != nil { + // Wait for input loop to finish. + if p.cancelReader.Cancel() { + if !kill { + p.waitForReadLoop() + } + } + _ = p.cancelReader.Close() + } + if p.renderer != nil { if kill { p.renderer.kill() @@ -686,7 +691,9 @@ func (p *Program) shutdown(kill bool) { } _ = p.restoreTerminalState() - p.finished <- struct{}{} + if !kill { + p.finished <- struct{}{} + } } // recoverFromPanic recovers from a panic, prints the stack trace, and restores From de4788dc763d5a6ce7ca555c5ee6fce3179dedc4 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 11 Sep 2024 16:11:48 -0400 Subject: [PATCH 11/61] docs: update readme badge images --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f80e04ea21..f994fe35bd 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@

Bubble Tea Title Treatment
Latest Release - GoDoc - Build Status + GoDoc + Build Status phorm.ai

From cfef82295698af8f3f9e1c0ece708c1347d8041a Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Mon, 19 Aug 2024 12:59:07 -0400 Subject: [PATCH 12/61] chore: deprecate high performance rendering cmds Performance rendering is very limited in what it can do and is very hard to implement. --- options.go | 3 +++ standard_renderer.go | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/options.go b/options.go index 06abf4a983..12e92e4e8e 100644 --- a/options.go +++ b/options.go @@ -185,6 +185,9 @@ func WithoutRenderer() ProgramOption { // // This feature is provisional, and may be changed or removed in a future version // of this package. +// +// Deprecated: this incurs a noticable performance hit. A future release will +// optimize ANSI automatically without the performance penalty. func WithANSICompressor() ProgramOption { return func(p *Program) { p.startupOptions |= withANSICompressor diff --git a/standard_renderer.go b/standard_renderer.go index 59448e1d41..d4f4418c79 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -546,6 +546,9 @@ func (r *standardRenderer) clearIgnoredLines() { // use in high-performance rendering, such as a pager that could potentially // be rendering very complicated ansi. In cases where the content is simpler // standard Bubble Tea rendering should suffice. +// +// Deprecated: This option is deprecated and will be removed in a future +// version of this package. func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary int) { r.mtx.Lock() defer r.mtx.Unlock() @@ -573,6 +576,9 @@ func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary // See note in insertTop() for caveats, how this function only makes sense for // full-window applications, and how it differs from the normal way we do // rendering in Bubble Tea. +// +// Deprecated: This option is deprecated and will be removed in a future +// version of this package. func (r *standardRenderer) insertBottom(lines []string, topBoundary, bottomBoundary int) { r.mtx.Lock() defer r.mtx.Unlock() @@ -657,6 +663,8 @@ type syncScrollAreaMsg struct { // should also be called on resize (WindowSizeMsg). // // For high-performance, scroll-based rendering only. +// +// Deprecated: This option will be removed in a future version of this package. func SyncScrollArea(lines []string, topBoundary int, bottomBoundary int) Cmd { return func() Msg { return syncScrollAreaMsg{ @@ -673,6 +681,8 @@ type clearScrollAreaMsg struct{} // those lines to the main rendering routine. // // For high-performance, scroll-based rendering only. +// +// Deprecated: This option will be removed in a future version of this package. func ClearScrollArea() Msg { return clearScrollAreaMsg{} } @@ -688,6 +698,8 @@ type scrollUpMsg struct { // from view. // // For high-performance, scroll-based rendering only. +// +// Deprecated: This option will be removed in a future version of this package. func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd { return func() Msg { return scrollUpMsg{ @@ -709,6 +721,8 @@ type scrollDownMsg struct { // disappear from view. // // For high-performance, scroll-based rendering only. +// +// Deprecated: This option will be removed in a future version of this package. func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd { return func() Msg { return scrollDownMsg{ From 69ecd8542ad5eabcdb6e593cde165c228391afac Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 11 Sep 2024 16:53:24 -0400 Subject: [PATCH 13/61] chore(examples): remove performance rendering portion of pager example --- examples/pager/main.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/examples/pager/main.go b/examples/pager/main.go index 12a71a316f..6969f01965 100644 --- a/examples/pager/main.go +++ b/examples/pager/main.go @@ -13,14 +13,6 @@ import ( "github.com/charmbracelet/lipgloss" ) -// You generally won't need this unless you're processing stuff with -// complicated ANSI escape sequences. Turn it on if you notice flickering. -// -// Also keep in mind that high performance rendering only works for programs -// that use the full size of the terminal. We're enabling that below with -// tea.EnterAltScreen(). -const useHighPerformanceRenderer = false - var ( titleStyle = func() lipgloss.Style { b := lipgloss.RoundedBorder() @@ -70,27 +62,12 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // here. m.viewport = viewport.New(msg.Width, msg.Height-verticalMarginHeight) m.viewport.YPosition = headerHeight - m.viewport.HighPerformanceRendering = useHighPerformanceRenderer m.viewport.SetContent(m.content) m.ready = true - - // This is only necessary for high performance rendering, which in - // most cases you won't need. - // - // Render the viewport one line below the header. - m.viewport.YPosition = headerHeight + 1 } else { m.viewport.Width = msg.Width m.viewport.Height = msg.Height - verticalMarginHeight } - - if useHighPerformanceRenderer { - // Render (or re-render) the whole viewport. Necessary both to - // initialize the viewport and when the window is resized. - // - // This is needed for high-performance rendering only. - cmds = append(cmds, viewport.Sync(m.viewport)) - } } // Handle keyboard and mouse events in the viewport From 2dd30e5eb35e0f4ed672fc7249c7bd16d674b9e7 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Thu, 12 Sep 2024 11:59:58 -0300 Subject: [PATCH 14/61] chore(deps): bump golang.org/x/sys from 0.24.0 to 0.25.0 Signed-off-by: Carlos Alexandro Becker --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- tutorials/go.mod | 9 +++------ tutorials/go.sum | 19 ++++++------------- 6 files changed, 15 insertions(+), 25 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 3a2c31e0cf..ab315c6699 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -42,7 +42,7 @@ require ( github.com/yuin/goldmark-emoji v1.0.3 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index b9b648f1ae..5237991f64 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -80,8 +80,8 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= diff --git a/go.mod b/go.mod index cfe3556678..ec170e2010 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 github.com/muesli/cancelreader v0.2.2 golang.org/x/sync v0.8.0 - golang.org/x/sys v0.24.0 + golang.org/x/sys v0.25.0 ) require ( diff --git a/go.sum b/go.sum index 890268a9b3..307715f9ee 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,7 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= diff --git a/tutorials/go.mod b/tutorials/go.mod index 5926388114..280980ef3e 100644 --- a/tutorials/go.mod +++ b/tutorials/go.mod @@ -7,10 +7,8 @@ require github.com/charmbracelet/bubbletea v0.25.0 require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/lipgloss v0.13.0 // indirect - github.com/charmbracelet/x/ansi v0.1.4 // indirect - github.com/charmbracelet/x/input v0.1.0 // indirect - github.com/charmbracelet/x/term v0.1.1 // indirect - github.com/charmbracelet/x/windows v0.1.0 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -20,9 +18,8 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.13.0 // indirect ) diff --git a/tutorials/go.sum b/tutorials/go.sum index 0c580d35ed..843c748d4b 100644 --- a/tutorials/go.sum +++ b/tutorials/go.sum @@ -2,14 +2,10 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM= -github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/input v0.1.0 h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ= -github.com/charmbracelet/x/input v0.1.0/go.mod h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28= -github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= -github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= -github.com/charmbracelet/x/windows v0.1.0 h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4= -github.com/charmbracelet/x/windows v0.1.0/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -29,14 +25,11 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= From dbb00c1de72ecf954720d29861ffcd170400e9e3 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Mon, 16 Sep 2024 09:58:21 -0400 Subject: [PATCH 15/61] chore(deps): bump github.com/charmbracelet/x/ansi from 0.2.3 to 0.3.1 --- examples/go.mod | 2 +- examples/go.sum | 2 ++ go.mod | 2 +- go.sum | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index ab315c6699..0ac900b7ba 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,7 +22,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/ansi v0.3.1 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 5237991f64..8de7fdccf8 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -24,6 +24,8 @@ github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.1 h1:CRO6lc/6HCx2/D6S/GZ87jDvRvk6GtPyFP+IljkNtqI= +github.com/charmbracelet/x/ansi v0.3.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= diff --git a/go.mod b/go.mod index ec170e2010..ce95481951 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.13.0 - github.com/charmbracelet/x/ansi v0.2.3 + github.com/charmbracelet/x/ansi v0.3.1 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 diff --git a/go.sum b/go.sum index 307715f9ee..3d932586e2 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.1 h1:CRO6lc/6HCx2/D6S/GZ87jDvRvk6GtPyFP+IljkNtqI= +github.com/charmbracelet/x/ansi v0.3.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= From 315e55aea96ff8ff22c5fbd1e214b031462eec5b Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Mon, 16 Sep 2024 14:12:55 -0400 Subject: [PATCH 16/61] chore(deps): bump charmbracelet/x/ansi from 0.3.1 to 0.3.2 --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index ce95481951..f702eb712d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.13.0 - github.com/charmbracelet/x/ansi v0.3.1 + github.com/charmbracelet/x/ansi v0.3.2 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 diff --git a/go.sum b/go.sum index 3d932586e2..0fa0e9766e 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/ansi v0.3.1 h1:CRO6lc/6HCx2/D6S/GZ87jDvRvk6GtPyFP+IljkNtqI= -github.com/charmbracelet/x/ansi v0.3.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= From bd77483b4441220586615000a6eeee04c7678658 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 19 Sep 2024 15:44:31 -0700 Subject: [PATCH 17/61] chore: go mod tidy --- examples/go.mod | 2 +- examples/go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 0ac900b7ba..824d98afa8 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,7 +22,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.3.1 // indirect + github.com/charmbracelet/x/ansi v0.3.2 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 8de7fdccf8..de23189c39 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,10 +22,8 @@ github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/ansi v0.3.1 h1:CRO6lc/6HCx2/D6S/GZ87jDvRvk6GtPyFP+IljkNtqI= -github.com/charmbracelet/x/ansi v0.3.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= From 9f0b382f3d44126836f837fd0ebd0fda3797cc18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:01:26 -0300 Subject: [PATCH 18/61] chore(deps): bump golang.org/x/sys from 0.25.0 to 0.26.0 (#1177) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.25.0 to 0.26.0. - [Commits](https://github.com/golang/sys/compare/v0.25.0...v0.26.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f702eb712d..f903135cd5 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 github.com/muesli/cancelreader v0.2.2 golang.org/x/sync v0.8.0 - golang.org/x/sys v0.25.0 + golang.org/x/sys v0.26.0 ) require ( diff --git a/go.sum b/go.sum index 0fa0e9766e..9ba3582639 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,7 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= From f945f2e94c59119c94f424bd6ad7f4517fbbca8c Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 15 Oct 2024 16:58:47 -0400 Subject: [PATCH 19/61] chore(examples): go mod tidy --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 824d98afa8..0b5d95f2f1 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -42,7 +42,7 @@ require ( github.com/yuin/goldmark-emoji v1.0.3 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index de23189c39..4e77da7ea8 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -80,8 +80,8 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= From d928d8dcabcd4bca0efc22fb661de0cc27c66b21 Mon Sep 17 00:00:00 2001 From: bashbunni <15822994+bashbunni@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:58:27 -0700 Subject: [PATCH 20/61] docs: update contributing guidelines (#1186) * docs(contributing): use org contributing guidelines * fix(docs): fix link to contribution page * docs: use https for links, not http --- CONTRIBUTING.md | 13 ------------- README.md | 10 ++++++++-- 2 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 19ee18c766..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,13 +0,0 @@ -# Contributing - -Pull requests are welcome for any changes. - -Consider opening an issue for larger changes to get feedback on the idea from the team. - -If your change touches parts of the Bubble Tea renderer or internals, make sure -that all the examples in the `examples/` folder continue to run correctly. - -For commit messages, please use conventional commits[^1] to make it easier to -generate release notes. - -[^1]: https://www.conventionalcommits.org/en/v1.0.0 diff --git a/README.md b/README.md index f994fe35bd..4dbe75eb14 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,8 @@ look at the [Command Tutorial][cmd]. It's pretty simple. There are also several [Bubble Tea examples][examples] available and, of course, there are [Go Docs][docs]. -[cmd]: http://github.com/charmbracelet/bubbletea/tree/master/tutorials/commands/ -[examples]: http://github.com/charmbracelet/bubbletea/tree/master/examples +[cmd]: https://github.com/charmbracelet/bubbletea/tree/master/tutorials/commands/ +[examples]: https://github.com/charmbracelet/bubbletea/tree/master/examples [docs]: https://pkg.go.dev/github.com/charmbracelet/bubbletea?tab=doc ## Debugging @@ -354,6 +354,12 @@ For more applications built with Bubble Tea see [Charm & Friends][community]. Is there something cool you made with Bubble Tea you want to share? [PRs][community] are welcome! +## Contributing + +See [contributing][contribute]. + +[contribute]: https://github.com/charmbracelet/bubbletea/contribute + ## Feedback We’d love to hear your thoughts on this project. Feel free to drop us a note! From cd1e4d34a7e0232ea94afcc168eec107450aa332 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Sun, 20 Oct 2024 21:45:53 -0700 Subject: [PATCH 21/61] fix: exec tests on windows Windows doesn't have true/false binaries --- exec_test.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/exec_test.go b/exec_test.go index b5fbbfa3b0..d49f0cc543 100644 --- a/exec_test.go +++ b/exec_test.go @@ -3,6 +3,7 @@ package tea import ( "bytes" "os/exec" + "runtime" "testing" ) @@ -37,21 +38,12 @@ func (m *testExecModel) View() string { } func TestTeaExec(t *testing.T) { - tests := []struct { + type test struct { name string cmd string expectErr bool - }{ - { - name: "true", - cmd: "true", - expectErr: false, - }, - { - name: "false", - cmd: "false", - expectErr: true, - }, + } + tests := []test{ { name: "invalid command", cmd: "invalid", @@ -59,6 +51,21 @@ func TestTeaExec(t *testing.T) { }, } + if runtime.GOOS != "windows" { + tests = append(tests, []test{ + { + name: "true", + cmd: "true", + expectErr: false, + }, + { + name: "false", + cmd: "false", + expectErr: true, + }, + }...) + } + for _, test := range tests { t.Run(test.name, func(t *testing.T) { var buf bytes.Buffer From 566879aa33ce13f27a6bdab4a274e08be01bac9c Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Sun, 20 Oct 2024 21:51:35 -0700 Subject: [PATCH 22/61] fix(ci): run lint workflow on all platforms --- .github/workflows/lint-soft.yml | 59 +++++++++++++++++---------------- .github/workflows/lint.yml | 59 +++++++++++++++++---------------- 2 files changed, 62 insertions(+), 56 deletions(-) diff --git a/.github/workflows/lint-soft.yml b/.github/workflows/lint-soft.yml index 87d1e1f9b0..50484fb502 100644 --- a/.github/workflows/lint-soft.yml +++ b/.github/workflows/lint-soft.yml @@ -1,28 +1,31 @@ -name: lint-soft -on: - push: - pull_request: - -permissions: - contents: read - # Optional: allow read access to pull request. Use with `only-new-issues` option. - pull-requests: read - -jobs: - golangci: - name: lint-soft - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ^1 - - - uses: actions/checkout@v4 - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - # Optional: golangci-lint command line arguments. - args: --config .golangci-soft.yml --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true +name: lint-soft +on: + push: + pull_request: + +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + +jobs: + golangci: + name: lint-soft + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ^1 + + - uses: actions/checkout@v4 + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + # Optional: golangci-lint command line arguments. + args: --config .golangci-soft.yml --issues-exit-code=0 + # Optional: show only new issues if it's a pull request. The default value is `false`. + only-new-issues: true diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f617a5a281..a328399b60 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,28 +1,31 @@ -name: lint -on: - push: - pull_request: - -permissions: - contents: read - # Optional: allow read access to pull request. Use with `only-new-issues` option. - pull-requests: read - -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ^1 - - - uses: actions/checkout@v4 - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - # Optional: golangci-lint command line arguments. - #args: - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true +name: lint +on: + push: + pull_request: + +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + +jobs: + golangci: + name: lint + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ^1 + + - uses: actions/checkout@v4 + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + # Optional: golangci-lint command line arguments. + #args: + # Optional: show only new issues if it's a pull request. The default value is `false`. + only-new-issues: true From 12b04c5d6001056875bc712f81fa1efd470fa592 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 22 Oct 2024 17:46:08 -0400 Subject: [PATCH 23/61] feat(ci): use meta lint workflow This replaces the existing lint workflow and config with the one from the meta repository. --- .github/workflows/lint.yml | 39 +++++++------------------------- .golangci-soft.yml | 46 -------------------------------------- .golangci.yml | 30 ------------------------- 3 files changed, 8 insertions(+), 107 deletions(-) delete mode 100644 .golangci-soft.yml delete mode 100644 .golangci.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a328399b60..a1d6d0e512 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,31 +1,8 @@ -name: lint -on: - push: - pull_request: - -permissions: - contents: read - # Optional: allow read access to pull request. Use with `only-new-issues` option. - pull-requests: read - -jobs: - golangci: - name: lint - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ^1 - - - uses: actions/checkout@v4 - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - # Optional: golangci-lint command line arguments. - #args: - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true +name: lint +on: + push: + pull_request: + +jobs: + lint: + uses: charmbracelet/meta/.github/workflows/lint.yml@main diff --git a/.golangci-soft.yml b/.golangci-soft.yml deleted file mode 100644 index 1b6824bb2d..0000000000 --- a/.golangci-soft.yml +++ /dev/null @@ -1,46 +0,0 @@ -run: - tests: false - -issues: - include: - - EXC0001 - - EXC0005 - - EXC0011 - - EXC0012 - - EXC0013 - - max-issues-per-linter: 0 - max-same-issues: 0 - -linters: - enable: - # - dupl - - exhaustive - # - exhaustivestruct - - goconst - - godot - - godox - - gomnd - - gomoddirectives - - goprintffuncname - # - lll - - misspell - - nakedret - - nestif - - noctx - - nolintlint - - prealloc - - wrapcheck - - # disable default linters, they are already enabled in .golangci.yml - disable: - - deadcode - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - structcheck - - typecheck - - unused - - varcheck diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index 3affce9147..0000000000 --- a/.golangci.yml +++ /dev/null @@ -1,30 +0,0 @@ -run: - tests: false - -issues: - include: - - EXC0001 - - EXC0005 - - EXC0011 - - EXC0012 - - EXC0013 - - max-issues-per-linter: 0 - max-same-issues: 0 - -linters: - enable: - - bodyclose - - exportloopref - - gofumpt - - goimports - - gosec - - nilerr - - predeclared - - revive - - rowserrcheck - - sqlclosecheck - - tparallel - - unconvert - - unparam - - whitespace From 1c01f2b1fc9039df02ac968cefc41808fc05f8b3 Mon Sep 17 00:00:00 2001 From: bashbunni Date: Wed, 23 Oct 2024 08:04:55 -0700 Subject: [PATCH 24/61] chore(lint): remove lint-soft; use meta --- .github/workflows/lint-soft.yml | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 .github/workflows/lint-soft.yml diff --git a/.github/workflows/lint-soft.yml b/.github/workflows/lint-soft.yml deleted file mode 100644 index 50484fb502..0000000000 --- a/.github/workflows/lint-soft.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: lint-soft -on: - push: - pull_request: - -permissions: - contents: read - # Optional: allow read access to pull request. Use with `only-new-issues` option. - pull-requests: read - -jobs: - golangci: - name: lint-soft - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ^1 - - - uses: actions/checkout@v4 - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - # Optional: golangci-lint command line arguments. - args: --config .golangci-soft.yml --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true From 2b4accc77a4c9b929fcfd6f42783036e19c50903 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Oct 2024 11:05:13 -0400 Subject: [PATCH 25/61] chore(deps): bump ansi from 0.3.2 to 0.4.0 --- go.mod | 2 +- go.sum | 2 ++ standard_renderer.go | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index f903135cd5..ff98c1d080 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.13.0 - github.com/charmbracelet/x/ansi v0.3.2 + github.com/charmbracelet/x/ansi v0.4.0 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 diff --git a/go.sum b/go.sum index 9ba3582639..2a4befce19 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= +github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= diff --git a/standard_renderer.go b/standard_renderer.go index d4f4418c79..0cb0ef374b 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -276,7 +276,7 @@ func (r *standardRenderer) flush() { // This case fixes a bug in macOS terminal. In other terminals the // other case seems to do the job regardless of whether or not we're // using the full terminal window. - buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) + buf.WriteString(ansi.SetCursorPosition(0, r.linesRendered)) } else { buf.WriteString(ansi.CursorLeft(r.width)) } @@ -312,8 +312,8 @@ func (r *standardRenderer) clearScreen() { r.mtx.Lock() defer r.mtx.Unlock() - r.execute(ansi.EraseEntireDisplay) - r.execute(ansi.MoveCursorOrigin) + r.execute(ansi.EraseEntireScreen) + r.execute(ansi.CursorOrigin) r.repaint() } @@ -342,8 +342,8 @@ func (r *standardRenderer) enterAltScreen() { // // Note: we can't use r.clearScreen() here because the mutex is already // locked. - r.execute(ansi.EraseEntireDisplay) - r.execute(ansi.MoveCursorOrigin) + r.execute(ansi.EraseEntireScreen) + r.execute(ansi.CursorOrigin) // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility @@ -516,7 +516,7 @@ func (r *standardRenderer) setIgnoredLines(from int, to int) { } buf.WriteString(ansi.CursorUp1) } - buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) // put cursor back + buf.WriteString(ansi.SetCursorPosition(0, r.linesRendered)) // put cursor back _, _ = r.out.Write(buf.Bytes()) } } @@ -556,13 +556,13 @@ func (r *standardRenderer) insertTop(lines []string, topBoundary, bottomBoundary buf := &bytes.Buffer{} buf.WriteString(ansi.SetScrollingRegion(topBoundary, bottomBoundary)) - buf.WriteString(ansi.MoveCursor(topBoundary, 0)) + buf.WriteString(ansi.SetCursorPosition(0, topBoundary)) buf.WriteString(ansi.InsertLine(len(lines))) _, _ = buf.WriteString(strings.Join(lines, "\r\n")) buf.WriteString(ansi.SetScrollingRegion(0, r.height)) // Move cursor back to where the main rendering routine expects it to be - buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) + buf.WriteString(ansi.SetCursorPosition(0, r.linesRendered)) _, _ = r.out.Write(buf.Bytes()) } @@ -586,12 +586,12 @@ func (r *standardRenderer) insertBottom(lines []string, topBoundary, bottomBound buf := &bytes.Buffer{} buf.WriteString(ansi.SetScrollingRegion(topBoundary, bottomBoundary)) - buf.WriteString(ansi.MoveCursor(bottomBoundary, 0)) + buf.WriteString(ansi.SetCursorPosition(0, bottomBoundary)) _, _ = buf.WriteString("\r\n" + strings.Join(lines, "\r\n")) buf.WriteString(ansi.SetScrollingRegion(0, r.height)) // Move cursor back to where the main rendering routine expects it to be - buf.WriteString(ansi.MoveCursor(r.linesRendered, 0)) + buf.WriteString(ansi.SetCursorPosition(0, r.linesRendered)) _, _ = r.out.Write(buf.Bytes()) } From fc066c0f1316855c129ab004812fbf2570295c6f Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Oct 2024 11:05:38 -0400 Subject: [PATCH 26/61] chore(examples): go mod tidy --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 0b5d95f2f1..b93bab30b5 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -22,7 +22,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.3.2 // indirect + github.com/charmbracelet/x/ansi v0.4.0 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 4e77da7ea8..7542e54054 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,8 +22,8 @@ github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= -github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= +github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= From 3209d62ae751da63a38237666d6706ab7c9f0006 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Oct 2024 12:15:10 -0400 Subject: [PATCH 27/61] feat(ci): use meta lint-sync workflow to sync linter config This adds a new workflow that runs manually or every week to sync the linter configuration from the meta repo. It will simply open a PR with the changes, which can be reviewed and merged as needed. --- .github/workflows/lint-sync.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/lint-sync.yml diff --git a/.github/workflows/lint-sync.yml b/.github/workflows/lint-sync.yml new file mode 100644 index 0000000000..ecf8580246 --- /dev/null +++ b/.github/workflows/lint-sync.yml @@ -0,0 +1,14 @@ +name: lint-sync +on: + schedule: + # every Sunday at midnight + - cron: "0 0 * * 0" + workflow_dispatch: # allows manual triggering + +permissions: + contents: write + pull-requests: write + +jobs: + lint: + uses: charmbracelet/meta/.github/workflows/lint-sync.yml@main From c07fa72e4f475b7fc5897dafc1efe68b2519ecf5 Mon Sep 17 00:00:00 2001 From: aymanbagabas <3187948+aymanbagabas@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:35:53 +0000 Subject: [PATCH 28/61] chore(ci): sync golangci-lint config --- .golangci.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000..d6789e014c --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,28 @@ +run: + tests: false + +issues: + include: + - EXC0001 + - EXC0005 + - EXC0011 + - EXC0012 + - EXC0013 + + max-issues-per-linter: 0 + max-same-issues: 0 + +linters: + enable: + - bodyclose + - gofumpt + - goimports + - gosec + - nilerr + - revive + - rowserrcheck + - sqlclosecheck + - tparallel + - unconvert + - unparam + - whitespace From 0ab3eac355c5f68ffdfebb6355b3c9c6a3fc7161 Mon Sep 17 00:00:00 2001 From: meowgorithm <25087+meowgorithm@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:52:09 +0000 Subject: [PATCH 29/61] chore(ci): sync golangci-lint config --- .golangci-soft.yml | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .golangci-soft.yml diff --git a/.golangci-soft.yml b/.golangci-soft.yml new file mode 100644 index 0000000000..8783713710 --- /dev/null +++ b/.golangci-soft.yml @@ -0,0 +1,40 @@ +run: + tests: false + +issues: + include: + - EXC0001 + - EXC0005 + - EXC0011 + - EXC0012 + - EXC0013 + + max-issues-per-linter: 0 + max-same-issues: 0 + +linters: + enable: + - exhaustive + - goconst + - godot + - godox + - mnd + - gomoddirectives + - goprintffuncname + - misspell + - nakedret + - nestif + - noctx + - nolintlint + - prealloc + - wrapcheck + + # disable default linters, they are already enabled in .golangci.yml + disable: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - typecheck + - unused From 1212e505d0c50c5ffaf87166cb41f42bac23aa69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:57:53 +0000 Subject: [PATCH 30/61] chore(deps): bump github.com/charmbracelet/lipgloss in /examples (#1198) --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index b93bab30b5..67f2c9adaa 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -9,7 +9,7 @@ require ( github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/harmonica v0.2.0 - github.com/charmbracelet/lipgloss v0.13.0 + github.com/charmbracelet/lipgloss v0.13.1 github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 github.com/lucasb-eyer/go-colorful v1.2.0 diff --git a/examples/go.sum b/examples/go.sum index 7542e54054..a5d1e5b3ed 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -20,8 +20,8 @@ github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= 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.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= -github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= +github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= From 9f015c50fa32420753a4ef3ee33b983ac093c5f7 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Mon, 28 Oct 2024 09:22:18 -0300 Subject: [PATCH 31/61] chore(deps): update lipgloss Signed-off-by: Carlos Alexandro Becker --- go.mod | 2 +- go.sum | 6 ++---- tutorials/go.mod | 6 +++--- tutorials/go.sum | 12 ++++++------ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index ff98c1d080..fa0e943061 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/charmbracelet/bubbletea go 1.18 require ( - github.com/charmbracelet/lipgloss v0.13.0 + github.com/charmbracelet/lipgloss v0.13.1 github.com/charmbracelet/x/ansi v0.4.0 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f diff --git a/go.sum b/go.sum index 2a4befce19..b9c3ac358b 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= -github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= -github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= +github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= diff --git a/tutorials/go.mod b/tutorials/go.mod index 280980ef3e..2d301fdb45 100644 --- a/tutorials/go.mod +++ b/tutorials/go.mod @@ -6,8 +6,8 @@ require github.com/charmbracelet/bubbletea v0.25.0 require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/lipgloss v0.13.0 // indirect - github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/lipgloss v0.13.1 // indirect + github.com/charmbracelet/x/ansi v0.4.0 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -19,7 +19,7 @@ require ( github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.13.0 // indirect ) diff --git a/tutorials/go.sum b/tutorials/go.sum index 843c748d4b..8906a00eca 100644 --- a/tutorials/go.sum +++ b/tutorials/go.sum @@ -1,9 +1,9 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= -github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= +github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= +github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= +github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= @@ -29,7 +29,7 @@ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= From f2e01145fe92c9744d40f9fe87544df51a84a4dc Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Tue, 29 Oct 2024 12:30:58 -0400 Subject: [PATCH 32/61] docs(examples): fix panics in table-width example --- examples/table-resize/main.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/table-resize/main.go b/examples/table-resize/main.go index 762211c0d4..01aae3f4f1 100644 --- a/examples/table-resize/main.go +++ b/examples/table-resize/main.go @@ -104,7 +104,12 @@ func main() { return headerStyle } - if rows[row-1][1] == "Pikachu" { + rowIndex := row - 1 + if rowIndex < 0 || rowIndex >= len(rows) { + return baseStyle + } + + if rows[rowIndex][1] == "Pikachu" { return selectedStyle } @@ -117,7 +122,14 @@ func main() { c = dimTypeColors } - color := c[fmt.Sprint(rows[row-1][col])] + if col >= len(rows[rowIndex]) { + return baseStyle + } + + color, ok := c[rows[rowIndex][col]] + if !ok { + return baseStyle + } return baseStyle.Foreground(color) } From 129d5ebad90a7462f7f5bb43eba9cac26d3e2ca9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:41:07 -0400 Subject: [PATCH 33/61] chore(deps): bump github.com/charmbracelet/x/ansi from 0.4.0 to 0.4.2 (#1214) Bumps [github.com/charmbracelet/x/ansi](https://github.com/charmbracelet/x) from 0.4.0 to 0.4.2. - [Release notes](https://github.com/charmbracelet/x/releases) - [Commits](https://github.com/charmbracelet/x/compare/ansi/v0.4.0...ansi/v0.4.2) --- updated-dependencies: - dependency-name: github.com/charmbracelet/x/ansi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fa0e943061..40449e3303 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v0.13.1 - github.com/charmbracelet/x/ansi v0.4.0 + github.com/charmbracelet/x/ansi v0.4.2 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 diff --git a/go.sum b/go.sum index b9c3ac358b..fea46d58bd 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= -github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= -github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= +github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= From 0cef3c7896a8393f461c3d6c4ef7df5aefa77db1 Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Sat, 7 Sep 2024 03:48:39 +0200 Subject: [PATCH 34/61] feat(render): remove flickering --- standard_renderer.go | 64 ++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/standard_renderer.go b/standard_renderer.go index 0cb0ef374b..70943811ba 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -168,6 +168,9 @@ func (r *standardRenderer) flush() { // Output buffer buf := &bytes.Buffer{} + // Moving to the begining of the section, that we rendered. + buf.WriteString(ansi.CursorUp(r.linesRendered-1) + ansi.CursorLeft(r.width)) + newLines := strings.Split(r.buf.String(), "\n") // If we know the output's height, we can use it to determine how many @@ -179,64 +182,25 @@ func (r *standardRenderer) flush() { } numLinesThisFlush := len(newLines) - oldLines := strings.Split(r.lastRender, "\n") - skipLines := make(map[int]struct{}) flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive - // Clear any lines we painted in the last render. - if r.linesRendered > 0 { - for i := r.linesRendered - 1; i > 0; i-- { - // if we are clearing queued messages, we want to clear all lines, since - // printing messages allows for native terminal word-wrap, we - // don't have control over the queued lines - if flushQueuedMessages { - buf.WriteString(ansi.EraseEntireLine) - } else if (len(newLines) <= len(oldLines)) && (len(newLines) > i && len(oldLines) > i) && (newLines[i] == oldLines[i]) { - // If the number of lines we want to render hasn't increased and - // new line is the same as the old line we can skip rendering for - // this line as a performance optimization. - skipLines[i] = struct{}{} - } else if _, exists := r.ignoreLines[i]; !exists { - buf.WriteString(ansi.EraseEntireLine) - } - - buf.WriteString(ansi.CursorUp1) - } - - if _, exists := r.ignoreLines[0]; !exists { - // We need to return to the start of the line here to properly - // erase it. Going back the entire width of the terminal will - // usually be farther than we need to go, but terminal emulators - // will stop the cursor at the start of the line as a rule. - // - // We use this sequence in particular because it's part of the ANSI - // standard (whereas others are proprietary to, say, VT100/VT52). - // If cursor previous line (ESC[ + + F) were better supported - // we could use that above to eliminate this step. - buf.WriteString(ansi.CursorLeft(r.width)) - buf.WriteString(ansi.EraseEntireLine) - } - } - - // Merge the set of lines we're skipping as a rendering optimization with - // the set of lines we've explicitly asked the renderer to ignore. - for k, v := range r.ignoreLines { - skipLines[k] = v - } - if flushQueuedMessages { - // Dump the lines we've queued up for printing + // Dump the lines we've queued up for printing. for _, line := range r.queuedMessageLines { + + // Removing previousy rendered content at the end of line. + line = line + ansi.EraseLineRight + _, _ = buf.WriteString(line) _, _ = buf.WriteString("\r\n") } - // clear the queued message lines + // Clear the queued message lines. r.queuedMessageLines = []string{} } - // Paint new lines + // Paint new lines. for i := 0; i < len(newLines); i++ { - if _, skip := skipLines[i]; skip { + if _, skip := r.ignoreLines[i]; skip { // Unless this is the last line, move the cursor down. if i < len(newLines)-1 { buf.WriteString(ansi.CursorDown1) @@ -250,6 +214,9 @@ func (r *standardRenderer) flush() { line := newLines[i] + // Removing left over content from previous render at the end of the line. + line = line + ansi.EraseLineRight + // Truncate lines wider than the width of the window to avoid // wrapping, which will mess up rendering. If we don't have the // width of the window this will be ignored. @@ -270,6 +237,9 @@ func (r *standardRenderer) flush() { } r.linesRendered = numLinesThisFlush + // Clearing left over content from last render (if our new frame contains less lines). + buf.WriteString(ansi.EraseDisplayRight) + // Make sure the cursor is at the start of the last line to keep rendering // behavior consistent. if r.altScreenActive { From 2106895cd889c8d5a5b55048f340e6af2dc5b505 Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Sun, 8 Sep 2024 00:35:11 +0200 Subject: [PATCH 35/61] feat(render): update tests for non-flick rendering + optimisations --- screen_test.go | 18 +++++++++--------- standard_renderer.go | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/screen_test.go b/screen_test.go index 728cd9779f..db46bb6a9f 100644 --- a/screen_test.go +++ b/screen_test.go @@ -14,47 +14,47 @@ func TestClearMsg(t *testing.T) { { name: "clear_screen", cmds: []Cmd{ClearScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[1;1H\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[1;1H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen", cmds: []Cmd{EnterAltScreen, ExitAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen_autoexit", cmds: []Cmd{EnterAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\rsuccess\r\n\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", }, { name: "mouse_cellmotion", cmds: []Cmd{EnableMouseCellMotion}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1002h\x1b[?1006h\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1002h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "mouse_allmotion", cmds: []Cmd{EnableMouseAllMotion}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "mouse_disable", cmds: []Cmd{EnableMouseAllMotion, DisableMouse}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\x1b[?1002l\x1b[?1003l\x1b[?1006l\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\x1b[?1002l\x1b[?1003l\x1b[?1006l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "cursor_hide", cmds: []Cmd{HideCursor}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "cursor_hideshow", cmds: []Cmd{HideCursor, ShowCursor}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\x1b[?25h\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\x1b[?25h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "bp_stop_start", cmds: []Cmd{DisableBracketedPaste, EnableBracketedPaste}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?2004l\x1b[?2004h\rsuccess\r\n\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?2004l\x1b[?2004h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, } diff --git a/standard_renderer.go b/standard_renderer.go index 70943811ba..4dbbd36ffb 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -161,15 +161,17 @@ func (r *standardRenderer) flush() { defer r.mtx.Unlock() if r.buf.Len() == 0 || r.buf.String() == r.lastRender { - // Nothing to do + // Nothing to do. return } - // Output buffer + // Output buffer. buf := &bytes.Buffer{} // Moving to the begining of the section, that we rendered. - buf.WriteString(ansi.CursorUp(r.linesRendered-1) + ansi.CursorLeft(r.width)) + if r.linesRendered > 0 { + buf.WriteString(ansi.CursorUp(r.linesRendered - 1)) + } newLines := strings.Split(r.buf.String(), "\n") @@ -214,7 +216,7 @@ func (r *standardRenderer) flush() { line := newLines[i] - // Removing left over content from previous render at the end of the line. + // Removing previousy rendered content at the end of line. line = line + ansi.EraseLineRight // Truncate lines wider than the width of the window to avoid @@ -235,10 +237,13 @@ func (r *standardRenderer) flush() { } } } - r.linesRendered = numLinesThisFlush - // Clearing left over content from last render (if our new frame contains less lines). - buf.WriteString(ansi.EraseDisplayRight) + // Clearing left over content from last render. + if r.linesRendered > numLinesThisFlush { + buf.WriteString(ansi.EraseDisplayRight) + } + + r.linesRendered = numLinesThisFlush // Make sure the cursor is at the start of the last line to keep rendering // behavior consistent. From 9ec9ad96056a4601d381f5a5538495574d6a8200 Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Sun, 8 Sep 2024 02:37:25 +0200 Subject: [PATCH 36/61] feat(render): fix typo --- standard_renderer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard_renderer.go b/standard_renderer.go index 4dbbd36ffb..dba91877f3 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -168,7 +168,7 @@ func (r *standardRenderer) flush() { // Output buffer. buf := &bytes.Buffer{} - // Moving to the begining of the section, that we rendered. + // Moving to the beginning of the section, that we rendered. if r.linesRendered > 0 { buf.WriteString(ansi.CursorUp(r.linesRendered - 1)) } From e44d9c6af253dde1208d6eeaf3a86570cdd2e291 Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Sun, 15 Sep 2024 02:09:59 +0200 Subject: [PATCH 37/61] update golden output --- examples/simple/testdata/TestApp.golden | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/simple/testdata/TestApp.golden b/examples/simple/testdata/TestApp.golden index 413aee46d6..cb6dc1af96 100644 --- a/examples/simple/testdata/TestApp.golden +++ b/examples/simple/testdata/TestApp.golden @@ -1,5 +1,7 @@ -[?25l[?2004h Hi. This program will exit in 10 seconds. - -To quit sooner press ctrl-c, or press ctrl-z to suspend... -Hi. This program will exit in 9 seconds. - [?2004l[?25h[?1002l[?1003l[?1006l \ No newline at end of file +[?25l[?2004h Hi. This program will exit in 10 seconds. + +To quit sooner press ctrl-c, or press ctrl-z to suspend... +Hi. This program will exit in 9 seconds. + +To quit sooner press ctrl-c, or press ctrl-z to suspend... + [?2004l[?25h[?1002l[?1003l[?1006l \ No newline at end of file From 4f161cdb4b2fe0d3bc60e05b696bbc3adde0355e Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Mon, 16 Sep 2024 17:57:32 +0200 Subject: [PATCH 38/61] feat(render): upd EraseDisplayRight --- standard_renderer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard_renderer.go b/standard_renderer.go index dba91877f3..f89e0be88c 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -240,7 +240,7 @@ func (r *standardRenderer) flush() { // Clearing left over content from last render. if r.linesRendered > numLinesThisFlush { - buf.WriteString(ansi.EraseDisplayRight) + buf.WriteString(ansi.EraseDisplayBelow) } r.linesRendered = numLinesThisFlush From 3dfbcd9c9bb79ea7faa7ab021d688da0d963fe4c Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Wed, 18 Sep 2024 04:11:09 +0200 Subject: [PATCH 39/61] feat(render): skipping lines from previous frame --- examples/simple/testdata/TestApp.golden | 4 +- standard_renderer.go | 53 ++++++++++++++----------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/examples/simple/testdata/TestApp.golden b/examples/simple/testdata/TestApp.golden index cb6dc1af96..6664a0eed0 100644 --- a/examples/simple/testdata/TestApp.golden +++ b/examples/simple/testdata/TestApp.golden @@ -2,6 +2,4 @@  To quit sooner press ctrl-c, or press ctrl-z to suspend... Hi. This program will exit in 9 seconds. - -To quit sooner press ctrl-c, or press ctrl-z to suspend... - [?2004l[?25h[?1002l[?1003l[?1006l \ No newline at end of file + [?2004l[?25h[?1002l[?1003l[?1006l \ No newline at end of file diff --git a/standard_renderer.go b/standard_renderer.go index f89e0be88c..48b44c4669 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -174,6 +174,7 @@ func (r *standardRenderer) flush() { } newLines := strings.Split(r.buf.String(), "\n") + oldLines := strings.Split(r.lastRender, "\n") // If we know the output's height, we can use it to determine how many // lines we can render. We drop lines from the top of the render buffer if @@ -202,39 +203,43 @@ func (r *standardRenderer) flush() { // Paint new lines. for i := 0; i < len(newLines); i++ { - if _, skip := r.ignoreLines[i]; skip { + canSkip := !flushQueuedMessages && // Queuing messages triggers repaint -> we don't have access to previous frame content. + len(oldLines) > i && oldLines[i] == newLines[i] // Previously rendered line is the same. + + if _, ignore := r.ignoreLines[i]; ignore || canSkip { // Unless this is the last line, move the cursor down. if i < len(newLines)-1 { buf.WriteString(ansi.CursorDown1) } - } else { - if i == 0 && r.lastRender == "" { - // On first render, reset the cursor to the start of the line - // before writing anything. - buf.WriteByte('\r') - } + continue + } - line := newLines[i] + if i == 0 && r.lastRender == "" { + // On first render, reset the cursor to the start of the line + // before writing anything. + buf.WriteByte('\r') + } - // Removing previousy rendered content at the end of line. - line = line + ansi.EraseLineRight + line := newLines[i] - // Truncate lines wider than the width of the window to avoid - // wrapping, which will mess up rendering. If we don't have the - // width of the window this will be ignored. - // - // Note that on Windows we only get the width of the window on - // program initialization, so after a resize this won't perform - // correctly (signal SIGWINCH is not supported on Windows). - if r.width > 0 { - line = ansi.Truncate(line, r.width, "") - } + // Removing previousy rendered content at the end of line. + line = line + ansi.EraseLineRight - _, _ = buf.WriteString(line) + // Truncate lines wider than the width of the window to avoid + // wrapping, which will mess up rendering. If we don't have the + // width of the window this will be ignored. + // + // Note that on Windows we only get the width of the window on + // program initialization, so after a resize this won't perform + // correctly (signal SIGWINCH is not supported on Windows). + if r.width > 0 { + line = ansi.Truncate(line, r.width, "") + } - if i < len(newLines)-1 { - _, _ = buf.WriteString("\r\n") - } + _, _ = buf.WriteString(line) + + if i < len(newLines)-1 { + _, _ = buf.WriteString("\r\n") } } From dcb05b0cb3cf982a351961c188b91c2f20daad15 Mon Sep 17 00:00:00 2001 From: Konstantin Antonov Date: Tue, 15 Oct 2024 22:31:40 +0200 Subject: [PATCH 40/61] fix single-line CursorUp(0) --- standard_renderer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard_renderer.go b/standard_renderer.go index 48b44c4669..05e2f0e114 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -169,7 +169,7 @@ func (r *standardRenderer) flush() { buf := &bytes.Buffer{} // Moving to the beginning of the section, that we rendered. - if r.linesRendered > 0 { + if r.linesRendered > 1 { buf.WriteString(ansi.CursorUp(r.linesRendered - 1)) } From 9bafc58cc877f352240250bf2bf342ad900c8448 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Oct 2024 12:42:46 -0400 Subject: [PATCH 41/61] fix: update standard_renderer.go --- standard_renderer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard_renderer.go b/standard_renderer.go index 05e2f0e114..1121af88e5 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -245,7 +245,7 @@ func (r *standardRenderer) flush() { // Clearing left over content from last render. if r.linesRendered > numLinesThisFlush { - buf.WriteString(ansi.EraseDisplayBelow) + buf.WriteString(ansi.EraseScreenBelow) } r.linesRendered = numLinesThisFlush From af9690711ad76e8c662a1b56ecc0c940a9ae5837 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:58:27 -0400 Subject: [PATCH 42/61] chore(ci): sync golangci-lint config (#1221) Co-authored-by: aymanbagabas <3187948+aymanbagabas@users.noreply.github.com> --- .golangci-soft.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci-soft.yml b/.golangci-soft.yml index 8783713710..8bd7c5c98a 100644 --- a/.golangci-soft.yml +++ b/.golangci-soft.yml @@ -36,5 +36,4 @@ linters: - govet - ineffassign - staticcheck - - typecheck - unused From 5f70edd7873cccfc82de75a624b1b28305c9be4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:03:17 -0400 Subject: [PATCH 43/61] chore(ci): sync golangci-lint config (#1222) Co-authored-by: aymanbagabas <3187948+aymanbagabas@users.noreply.github.com> --- .golangci-soft.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.golangci-soft.yml b/.golangci-soft.yml index 8bd7c5c98a..d325d4fcc6 100644 --- a/.golangci-soft.yml +++ b/.golangci-soft.yml @@ -1,5 +1,6 @@ run: tests: false + issues-exit-code: 0 issues: include: From 2472d90201467bb911eb0ba37f4a9da69ad33209 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 31 Oct 2024 16:04:51 -0400 Subject: [PATCH 44/61] fix: remove unnecessary line break --- standard_renderer.go | 1 - 1 file changed, 1 deletion(-) diff --git a/standard_renderer.go b/standard_renderer.go index 1121af88e5..583e5b389e 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -190,7 +190,6 @@ func (r *standardRenderer) flush() { if flushQueuedMessages { // Dump the lines we've queued up for printing. for _, line := range r.queuedMessageLines { - // Removing previousy rendered content at the end of line. line = line + ansi.EraseLineRight From 3bbf24dec24acebdb32ef675cb9788c90206e911 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:19:21 -0400 Subject: [PATCH 45/61] chore(deps): bump github.com/charmbracelet/lipgloss in /examples (#1220) Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.13.1 to 1.0.0. - [Release notes](https://github.com/charmbracelet/lipgloss/releases) - [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml) - [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.13.1...v1.0.0) --- updated-dependencies: - dependency-name: github.com/charmbracelet/lipgloss dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/go.mod | 4 ++-- examples/go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 67f2c9adaa..5557aad7d5 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -9,7 +9,7 @@ require ( github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/harmonica v0.2.0 - github.com/charmbracelet/lipgloss v0.13.1 + github.com/charmbracelet/lipgloss v1.0.0 github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 github.com/fogleman/ease v0.0.0-20170301025033-8da417bf1776 github.com/lucasb-eyer/go-colorful v1.2.0 @@ -22,7 +22,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.4.0 // indirect + github.com/charmbracelet/x/ansi v0.4.2 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index a5d1e5b3ed..2c3de2dc45 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -20,10 +20,10 @@ github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= 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.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= -github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= -github.com/charmbracelet/x/ansi v0.4.0 h1:NqwHA4B23VwsDn4H3VcNX1W1tOmgnvY1NDx5tOXdnOU= -github.com/charmbracelet/x/ansi v0.4.0/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= +github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= From d6aee5bd5f9492b96f31969a09d1c38f21532120 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:19:40 -0400 Subject: [PATCH 46/61] chore(deps): bump github.com/charmbracelet/lipgloss from 0.13.1 to 1.0.0 (#1219) Bumps [github.com/charmbracelet/lipgloss](https://github.com/charmbracelet/lipgloss) from 0.13.1 to 1.0.0. - [Release notes](https://github.com/charmbracelet/lipgloss/releases) - [Changelog](https://github.com/charmbracelet/lipgloss/blob/master/.goreleaser.yml) - [Commits](https://github.com/charmbracelet/lipgloss/compare/v0.13.1...v1.0.0) --- updated-dependencies: - dependency-name: github.com/charmbracelet/lipgloss dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 40449e3303..cec66a6a70 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/charmbracelet/bubbletea go 1.18 require ( - github.com/charmbracelet/lipgloss v0.13.1 + github.com/charmbracelet/lipgloss v1.0.0 github.com/charmbracelet/x/ansi v0.4.2 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f diff --git a/go.sum b/go.sum index fea46d58bd..fb191d19a8 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/lipgloss v0.13.1 h1:Oik/oqDTMVA01GetT4JdEC033dNzWoQHdWnHnQmXE2A= -github.com/charmbracelet/lipgloss v0.13.1/go.mod h1:zaYVJ2xKSKEnTEEbX6uAHabh2d975RJ+0yfkFpRBz5U= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= From f4d1e0ead8047cc5557e638ed424e66e18a36c11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:55:52 +0000 Subject: [PATCH 47/61] chore(deps): bump github.com/charmbracelet/x/ansi from 0.4.2 to 0.4.5 (#1224) Bumps [github.com/charmbracelet/x/ansi](https://github.com/charmbracelet/x) from 0.4.2 to 0.4.5. - [Release notes](https://github.com/charmbracelet/x/releases) - [Commits](https://github.com/charmbracelet/x/compare/ansi/v0.4.2...ansi/v0.4.5) --- updated-dependencies: - dependency-name: github.com/charmbracelet/x/ansi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cec66a6a70..305c142be7 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v1.0.0 - github.com/charmbracelet/x/ansi v0.4.2 + github.com/charmbracelet/x/ansi v0.4.5 github.com/charmbracelet/x/term v0.2.0 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 diff --git a/go.sum b/go.sum index fb191d19a8..f55c81f1c4 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= -github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= -github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= From 99b85ff94fbbf85dc1a0c8f5753e0b18f484816e Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 8 Nov 2024 11:14:39 -0500 Subject: [PATCH 48/61] fix: renderer: erase the rest of the line when it's shorter than the width When the cursor reaches the end of the line, any escape sequences that follow will only affect the last cell of the line. This is why we only erase the rest of the line when the line is shorter than the width of the terminal. Fixes: https://github.com/charmbracelet/bubbletea/issues/1225 Fixes: 0cef3c7896a8 (feat(render): remove flickering) --- standard_renderer.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/standard_renderer.go b/standard_renderer.go index 583e5b389e..f564b6a094 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -190,8 +190,15 @@ func (r *standardRenderer) flush() { if flushQueuedMessages { // Dump the lines we've queued up for printing. for _, line := range r.queuedMessageLines { - // Removing previousy rendered content at the end of line. - line = line + ansi.EraseLineRight + if ansi.StringWidth(line) < r.width { + // We only erase the rest of the line when the line is shorter than + // the width of the terminal. When the cursor reaches the end of + // the line, any escape sequences that follow will only affect the + // last cell of the line. + + // Removing previously rendered content at the end of line. + line = line + ansi.EraseLineRight + } _, _ = buf.WriteString(line) _, _ = buf.WriteString("\r\n") @@ -221,9 +228,6 @@ func (r *standardRenderer) flush() { line := newLines[i] - // Removing previousy rendered content at the end of line. - line = line + ansi.EraseLineRight - // Truncate lines wider than the width of the window to avoid // wrapping, which will mess up rendering. If we don't have the // width of the window this will be ignored. @@ -235,6 +239,16 @@ func (r *standardRenderer) flush() { line = ansi.Truncate(line, r.width, "") } + if ansi.StringWidth(line) < r.width { + // We only erase the rest of the line when the line is shorter than + // the width of the terminal. When the cursor reaches the end of + // the line, any escape sequences that follow will only affect the + // last cell of the line. + + // Removing previously rendered content at the end of line. + line = line + ansi.EraseLineRight + } + _, _ = buf.WriteString(line) if i < len(newLines)-1 { From 50249d492da0c103dfc37d2e47e1be49217479b1 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 8 Nov 2024 11:21:09 -0500 Subject: [PATCH 49/61] fix: screen_test.go: fix test cases for cursor movement Add window size msg to the test cases to fix the cursor movement test cases. --- screen_test.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/screen_test.go b/screen_test.go index db46bb6a9f..0d22943b68 100644 --- a/screen_test.go +++ b/screen_test.go @@ -14,12 +14,12 @@ func TestClearMsg(t *testing.T) { { name: "clear_screen", cmds: []Cmd{ClearScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[1;1H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[1;1H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen", cmds: []Cmd{EnterAltScreen, ExitAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen_autoexit", @@ -29,32 +29,32 @@ func TestClearMsg(t *testing.T) { { name: "mouse_cellmotion", cmds: []Cmd{EnableMouseCellMotion}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1002h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1002h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "mouse_allmotion", cmds: []Cmd{EnableMouseAllMotion}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "mouse_disable", cmds: []Cmd{EnableMouseAllMotion, DisableMouse}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\x1b[?1002l\x1b[?1003l\x1b[?1006l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\x1b[?1002l\x1b[?1003l\x1b[?1006l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "cursor_hide", cmds: []Cmd{HideCursor}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "cursor_hideshow", cmds: []Cmd{HideCursor, ShowCursor}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\x1b[?25h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?25l\x1b[?25h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "bp_stop_start", cmds: []Cmd{DisableBracketedPaste, EnableBracketedPaste}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?2004l\x1b[?2004h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?2004l\x1b[?2004h\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, } @@ -66,6 +66,7 @@ func TestClearMsg(t *testing.T) { m := &testModel{} p := NewProgram(m, WithInput(&in), WithOutput(&buf)) + test.cmds = append([]Cmd{func() Msg { return WindowSizeMsg{80, 24} }}, test.cmds...) test.cmds = append(test.cmds, Quit) go p.Send(test.cmds) From c78a084f81ea3011662876d8ae65752875f25aa3 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 8 Nov 2024 11:23:23 -0500 Subject: [PATCH 50/61] fix: renderer: use HomeCursorPosition instead of CursorOrigin --- standard_renderer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard_renderer.go b/standard_renderer.go index f564b6a094..2585bccad6 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -306,7 +306,7 @@ func (r *standardRenderer) clearScreen() { defer r.mtx.Unlock() r.execute(ansi.EraseEntireScreen) - r.execute(ansi.CursorOrigin) + r.execute(ansi.HomeCursorPosition) r.repaint() } @@ -336,7 +336,7 @@ func (r *standardRenderer) enterAltScreen() { // Note: we can't use r.clearScreen() here because the mutex is already // locked. r.execute(ansi.EraseEntireScreen) - r.execute(ansi.CursorOrigin) + r.execute(ansi.HomeCursorPosition) // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility From e16a768eabe59bb0e4d4fe7a40439e27346dcf66 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 8 Nov 2024 11:27:36 -0500 Subject: [PATCH 51/61] fix: screen_test.go: fix test cases for ClearScreen and EnterAltScreen --- screen_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/screen_test.go b/screen_test.go index 0d22943b68..0a7facb422 100644 --- a/screen_test.go +++ b/screen_test.go @@ -14,17 +14,17 @@ func TestClearMsg(t *testing.T) { { name: "clear_screen", cmds: []Cmd{ClearScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[1;1H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[2J\x1b[H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen", cmds: []Cmd{EnterAltScreen, ExitAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[H\x1b[?25l\x1b[?1049l\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[80D\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l", }, { name: "altscreen_autoexit", cmds: []Cmd{EnterAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[1;1H\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[H\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", }, { name: "mouse_cellmotion", From 5b65f9afee63a23935373397c858891ddf0e868d Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 8 Nov 2024 11:36:57 -0500 Subject: [PATCH 52/61] chore: go mod tidy --- examples/go.mod | 6 +++--- examples/go.sum | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 5557aad7d5..71a272838b 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -6,7 +6,7 @@ toolchain go1.22.5 require ( github.com/charmbracelet/bubbles v0.20.0 - github.com/charmbracelet/bubbletea v1.1.0 + github.com/charmbracelet/bubbletea v1.2.0 github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/harmonica v0.2.0 github.com/charmbracelet/lipgloss v1.0.0 @@ -22,7 +22,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-udiff v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/charmbracelet/x/ansi v0.4.2 // indirect + github.com/charmbracelet/x/ansi v0.4.5 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect @@ -44,7 +44,7 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/text v0.19.0 // indirect ) replace github.com/charmbracelet/bubbletea => ../ diff --git a/examples/go.sum b/examples/go.sum index 2c3de2dc45..3b70b3c3ef 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -22,8 +22,8 @@ github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= -github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= -github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAMdlwSltxJyULnrYbkZpp4k58Co7Tah3ciKhSNo0Q= github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= @@ -84,5 +84,5 @@ golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= From 790415e796bb02cc2425f6a66976889c0e6bf043 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:22:18 +0000 Subject: [PATCH 53/61] chore(deps): bump golang.org/x/sync from 0.8.0 to 0.9.0 (#1228) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.8.0 to 0.9.0. - [Commits](https://github.com/golang/sync/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 305c142be7..910fdf8d83 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/mattn/go-localereader v0.0.1 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 github.com/muesli/cancelreader v0.2.2 - golang.org/x/sync v0.8.0 + golang.org/x/sync v0.9.0 golang.org/x/sys v0.26.0 ) diff --git a/go.sum b/go.sum index f55c81f1c4..6ba9d79030 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1n github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= From 80508cff7528c85774e91867730ad13d12b57a3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:23:32 +0000 Subject: [PATCH 54/61] chore(deps): bump github.com/charmbracelet/x/term from 0.2.0 to 0.2.1 (#1229) Bumps [github.com/charmbracelet/x/term](https://github.com/charmbracelet/x) from 0.2.0 to 0.2.1. - [Release notes](https://github.com/charmbracelet/x/releases) - [Commits](https://github.com/charmbracelet/x/compare/ansi/v0.2.0...ansi/v0.2.1) --- updated-dependencies: - dependency-name: github.com/charmbracelet/x/term dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 910fdf8d83..a063377fee 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/charmbracelet/lipgloss v1.0.0 github.com/charmbracelet/x/ansi v0.4.5 - github.com/charmbracelet/x/term v0.2.0 + github.com/charmbracelet/x/term v0.2.1 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f github.com/mattn/go-localereader v0.0.1 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 diff --git a/go.sum b/go.sum index 6ba9d79030..3a12ae185b 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= -github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= -github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= From 1feb60b44b74d9a3a7dc54b90ffbecc8ffd6b40d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:24:12 +0000 Subject: [PATCH 55/61] chore(deps): bump golang.org/x/sys from 0.26.0 to 0.27.0 (#1230) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.26.0 to 0.27.0. - [Commits](https://github.com/golang/sys/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a063377fee..19f044c788 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 github.com/muesli/cancelreader v0.2.2 golang.org/x/sync v0.9.0 - golang.org/x/sys v0.26.0 + golang.org/x/sys v0.27.0 ) require ( diff --git a/go.sum b/go.sum index 3a12ae185b..a06dad2b1c 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,7 @@ golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= From 97fc4fada84eba82ccfce0ffcc1b9d6216fca05c Mon Sep 17 00:00:00 2001 From: Semih Buyukgungor Date: Tue, 12 Nov 2024 21:54:54 +0300 Subject: [PATCH 56/61] fix: incorrect line skipping in renderer flush (#1233) * fix line skip in flush * mod tidy in examples dir * reset lastRenderedLines on repaint * docs: add note * fix: simplify line skip logic --------- Co-authored-by: Ayman Bagabas --- examples/go.mod | 6 +++--- examples/go.sum | 12 ++++++------ standard_renderer.go | 15 ++++++++++----- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 71a272838b..2c57c939a1 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -24,7 +24,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/x/ansi v0.4.5 // indirect github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b // indirect - github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect @@ -41,8 +41,8 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.19.0 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 3b70b3c3ef..cef8c200a0 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -28,8 +28,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAM github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28 h1:sOWKNRjt8uOEVgPiJVIJCse1+mUDM2F/vYY6W0Go640= github.com/charmbracelet/x/exp/teatest v0.0.0-20240521184646-23081fb03b28/go.mod h1:l1w+LTJZCCozeGzMEWGxRw6Mo2DfcZUvupz8HGubdes= -github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= -github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -76,12 +76,12 @@ github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhb github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= diff --git a/standard_renderer.go b/standard_renderer.go index 2585bccad6..f30fc3592e 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -34,6 +34,7 @@ type standardRenderer struct { ticker *time.Ticker done chan struct{} lastRender string + lastRenderedLines []string linesRendered int useANSICompressor bool once sync.Once @@ -174,7 +175,6 @@ func (r *standardRenderer) flush() { } newLines := strings.Split(r.buf.String(), "\n") - oldLines := strings.Split(r.lastRender, "\n") // If we know the output's height, we can use it to determine how many // lines we can render. We drop lines from the top of the render buffer if @@ -184,7 +184,6 @@ func (r *standardRenderer) flush() { newLines = newLines[len(newLines)-r.height:] } - numLinesThisFlush := len(newLines) flushQueuedMessages := len(r.queuedMessageLines) > 0 && !r.altScreenActive if flushQueuedMessages { @@ -210,7 +209,7 @@ func (r *standardRenderer) flush() { // Paint new lines. for i := 0; i < len(newLines); i++ { canSkip := !flushQueuedMessages && // Queuing messages triggers repaint -> we don't have access to previous frame content. - len(oldLines) > i && oldLines[i] == newLines[i] // Previously rendered line is the same. + len(r.lastRenderedLines) > i && r.lastRenderedLines[i] == newLines[i] // Previously rendered line is the same. if _, ignore := r.ignoreLines[i]; ignore || canSkip { // Unless this is the last line, move the cursor down. @@ -257,11 +256,11 @@ func (r *standardRenderer) flush() { } // Clearing left over content from last render. - if r.linesRendered > numLinesThisFlush { + if r.linesRendered > len(newLines) { buf.WriteString(ansi.EraseScreenBelow) } - r.linesRendered = numLinesThisFlush + r.linesRendered = len(newLines) // Make sure the cursor is at the start of the last line to keep rendering // behavior consistent. @@ -276,6 +275,11 @@ func (r *standardRenderer) flush() { _, _ = r.out.Write(buf.Bytes()) r.lastRender = r.buf.String() + + // Save previously rendered lines for comparison in the next render. If we + // don't do this, we can't skip rendering lines that haven't changed. + // See https://github.com/charmbracelet/bubbletea/pull/1233 + r.lastRenderedLines = newLines r.buf.Reset() } @@ -299,6 +303,7 @@ func (r *standardRenderer) write(s string) { func (r *standardRenderer) repaint() { r.lastRender = "" + r.lastRenderedLines = nil } func (r *standardRenderer) clearScreen() { From 76b0f818b3174a3e9b77f93c19820d07855f13f4 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Wed, 13 Nov 2024 12:09:09 -0300 Subject: [PATCH 57/61] ci: fix goreleaser config (#1238) Signed-off-by: Carlos Alexandro Becker --- .gitignore | 1 + .goreleaser.yml | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9cc52352eb..abd7c0612b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ tutorials/basics/basics tutorials/commands/commands .idea coverage.txt +dist/ diff --git a/.goreleaser.yml b/.goreleaser.yml index 40d9f298db..3353d02029 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,6 +1,5 @@ +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json +version: 2 includes: - from_url: url: charmbracelet/meta/main/goreleaser-lib.yaml - -# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json - From 4ad07926d7ff00bc21a05b2536d82a7cc629225e Mon Sep 17 00:00:00 2001 From: Semih Buyukgungor Date: Tue, 19 Nov 2024 18:32:53 +0300 Subject: [PATCH 58/61] fix: cursor position adjustment after exiting alt screen (#1241) * fix cursor position handling after exiting alt screen mode * avoid moving cursor when lines rendered before alt screen is zero --- standard_renderer.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/standard_renderer.go b/standard_renderer.go index f30fc3592e..aa8524b840 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -57,6 +57,9 @@ type standardRenderer struct { // lines explicitly set not to render ignoreLines map[int]struct{} + + // lines rendered before entering alt screen mode + linesRenderedBeforeAltScreen int } // newRenderer creates a new renderer. Normally you'll want to initialize it @@ -334,6 +337,10 @@ func (r *standardRenderer) enterAltScreen() { r.altScreenActive = true r.execute(ansi.EnableAltScreenBuffer) + // Save the current line count before entering the alternate screen mode. + // This allows us to compare and adjust the cursor position when exiting the alternate screen. + r.linesRenderedBeforeAltScreen = r.linesRendered + // Ensure that the terminal is cleared, even when it doesn't support // alt screen (or alt screen support is disabled, like GNU screen by // default). @@ -366,6 +373,18 @@ func (r *standardRenderer) exitAltScreen() { r.altScreenActive = false r.execute(ansi.DisableAltScreenBuffer) + // Adjust cursor and screen + if r.linesRendered < r.linesRenderedBeforeAltScreen { + // If fewer lines were rendered in the alternate screen, move the cursor up + // to align with the previous normal screen position and clear any remaining lines. + r.execute(ansi.CursorUp(r.linesRenderedBeforeAltScreen - r.linesRendered)) + r.execute(ansi.EraseScreenBelow) + } else if r.linesRendered > r.linesRenderedBeforeAltScreen && r.linesRenderedBeforeAltScreen > 0 { + // If more lines were rendered in the alternate screen, move the cursor down + // to align with the new position. + r.execute(ansi.CursorDown(r.linesRendered - r.linesRenderedBeforeAltScreen)) + } + // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility // whenever we exit AltScreen. From bc15c1e093393390b9aeb4c8e8e9502f6443dd39 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 22 Nov 2024 14:21:05 -0500 Subject: [PATCH 59/61] chore: revert "fix: cursor position adjustment after exiting alt screen (#1241)" This reverts commit 4ad07926d7ff00bc21a05b2536d82a7cc629225e. --- standard_renderer.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/standard_renderer.go b/standard_renderer.go index aa8524b840..f30fc3592e 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -57,9 +57,6 @@ type standardRenderer struct { // lines explicitly set not to render ignoreLines map[int]struct{} - - // lines rendered before entering alt screen mode - linesRenderedBeforeAltScreen int } // newRenderer creates a new renderer. Normally you'll want to initialize it @@ -337,10 +334,6 @@ func (r *standardRenderer) enterAltScreen() { r.altScreenActive = true r.execute(ansi.EnableAltScreenBuffer) - // Save the current line count before entering the alternate screen mode. - // This allows us to compare and adjust the cursor position when exiting the alternate screen. - r.linesRenderedBeforeAltScreen = r.linesRendered - // Ensure that the terminal is cleared, even when it doesn't support // alt screen (or alt screen support is disabled, like GNU screen by // default). @@ -373,18 +366,6 @@ func (r *standardRenderer) exitAltScreen() { r.altScreenActive = false r.execute(ansi.DisableAltScreenBuffer) - // Adjust cursor and screen - if r.linesRendered < r.linesRenderedBeforeAltScreen { - // If fewer lines were rendered in the alternate screen, move the cursor up - // to align with the previous normal screen position and clear any remaining lines. - r.execute(ansi.CursorUp(r.linesRenderedBeforeAltScreen - r.linesRendered)) - r.execute(ansi.EraseScreenBelow) - } else if r.linesRendered > r.linesRenderedBeforeAltScreen && r.linesRenderedBeforeAltScreen > 0 { - // If more lines were rendered in the alternate screen, move the cursor down - // to align with the new position. - r.execute(ansi.CursorDown(r.linesRendered - r.linesRenderedBeforeAltScreen)) - } - // cmd.exe and other terminals keep separate cursor states for the AltScreen // and the main buffer. We have to explicitly reset the cursor visibility // whenever we exit AltScreen. From ede8caa9d4f588a4a2c744d8e135a1b444bf2ce9 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 22 Nov 2024 14:38:11 -0500 Subject: [PATCH 60/61] fix: renderer: keep a separate count of lines rendered in the alt screen We need to keep a separate count of lines rendered in the alt screen and inline mode. This is because when we enter alt screen mode, the cursor position is saved and the alt screen is cleared. Now when we exit the alt screen mode, the cursor position is restored so we don't need to move the cursor to the beginning of the section that we rendered. To fix this, we keep a separate count of lines rendered in the alt screen mode and inline mode. Related: https://github.com/charmbracelet/bubbletea/issues/1013 Fixes: https://github.com/charmbracelet/bubbletea/pull/1241 Fixes: https://github.com/charmbracelet/bubbletea/issues/1248 --- standard_renderer.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/standard_renderer.go b/standard_renderer.go index f30fc3592e..369f27f87d 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -36,6 +36,7 @@ type standardRenderer struct { lastRender string lastRenderedLines []string linesRendered int + altLinesRendered int useANSICompressor bool once sync.Once @@ -170,7 +171,9 @@ func (r *standardRenderer) flush() { buf := &bytes.Buffer{} // Moving to the beginning of the section, that we rendered. - if r.linesRendered > 1 { + if r.altScreenActive { + buf.WriteString(ansi.HomeCursorPosition) + } else if r.linesRendered > 1 { buf.WriteString(ansi.CursorUp(r.linesRendered - 1)) } @@ -255,12 +258,21 @@ func (r *standardRenderer) flush() { } } + lastLinesRendered := r.linesRendered + if r.altScreenActive { + lastLinesRendered = r.altLinesRendered + } + // Clearing left over content from last render. - if r.linesRendered > len(newLines) { + if lastLinesRendered > len(newLines) { buf.WriteString(ansi.EraseScreenBelow) } - r.linesRendered = len(newLines) + if r.altScreenActive { + r.altLinesRendered = len(newLines) + } else { + r.linesRendered = len(newLines) + } // Make sure the cursor is at the start of the last line to keep rendering // behavior consistent. @@ -268,7 +280,7 @@ func (r *standardRenderer) flush() { // This case fixes a bug in macOS terminal. In other terminals the // other case seems to do the job regardless of whether or not we're // using the full terminal window. - buf.WriteString(ansi.SetCursorPosition(0, r.linesRendered)) + buf.WriteString(ansi.SetCursorPosition(0, len(newLines))) } else { buf.WriteString(ansi.CursorLeft(r.width)) } @@ -352,6 +364,9 @@ func (r *standardRenderer) enterAltScreen() { r.execute(ansi.ShowCursor) } + // Entering the alt screen resets the lines rendered count. + r.altLinesRendered = 0 + r.repaint() } From 2ea49ddc4f36b8c47231ab0be31e40ca8676b050 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 22 Nov 2024 15:02:45 -0500 Subject: [PATCH 61/61] chore: update screen test --- screen_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen_test.go b/screen_test.go index 0a7facb422..6011d5199b 100644 --- a/screen_test.go +++ b/screen_test.go @@ -24,7 +24,7 @@ func TestClearMsg(t *testing.T) { { name: "altscreen_autoexit", cmds: []Cmd{EnterAltScreen}, - expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[H\x1b[?25l\rsuccess\x1b[0K\r\n\x1b[0K\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", + expected: "\x1b[?25l\x1b[?2004h\x1b[?1049h\x1b[2J\x1b[H\x1b[?25l\x1b[H\rsuccess\x1b[0K\r\n\x1b[0K\x1b[2;0H\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1049l\x1b[?25h", }, { name: "mouse_cellmotion",