diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dd84ea7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index d944991..c0e481b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,57 +1,20 @@
version: 2
-
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
- interval: "weekly"
- day: "monday"
- time: "05:00"
- timezone: "America/New_York"
+ interval: "daily"
labels:
- "dependencies"
commit-message:
prefix: "chore"
include: "scope"
- groups:
- all:
- patterns:
- - "*"
- ignore:
- - dependency-name: github.com/charmbracelet/bubbletea/v2
- versions:
- - v2.0.0-beta1
-
- package-ecosystem: "github-actions"
directory: "/"
schedule:
- interval: "weekly"
- day: "monday"
- time: "05:00"
- timezone: "America/New_York"
+ interval: "daily"
labels:
- "dependencies"
commit-message:
prefix: "chore"
include: "scope"
- groups:
- all:
- patterns:
- - "*"
-
- - package-ecosystem: "docker"
- directory: "/"
- schedule:
- interval: "weekly"
- day: "monday"
- time: "05:00"
- timezone: "America/New_York"
- labels:
- - "dependencies"
- commit-message:
- prefix: "chore"
- include: "scope"
- groups:
- all:
- patterns:
- - "*"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2330819..5be3fe8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,13 +1,53 @@
name: build
-on:
- push:
- branches:
- - main
- pull_request:
+on: [push, pull_request]
jobs:
build:
- uses: charmbracelet/meta/.github/workflows/build.yml@main
+ strategy:
+ matrix:
+ 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: ~1.21
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Download Go modules
+ run: go mod download
+
+ - name: Build
+ run: go build -v ./...
+
+ - name: Test
+ run: go test -v -cover -timeout=30s ./...
+
+ snapshot:
+ uses: charmbracelet/meta/.github/workflows/snapshot.yml@main
secrets:
- gh_pat: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+ goreleaser_key: ${{ secrets.GORELEASER_KEY }}
+
+ dependabot:
+ needs: [build]
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ contents: write
+ if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}}
+ steps:
+ - id: metadata
+ uses: dependabot/fetch-metadata@v2
+ with:
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
+ - run: |
+ gh pr review --approve "$PR_URL"
+ gh pr merge --squash --auto "$PR_URL"
+ env:
+ PR_URL: ${{github.event.pull_request.html_url}}
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
diff --git a/.github/workflows/dependabot-sync.yml b/.github/workflows/dependabot-sync.yml
deleted file mode 100644
index 9b08259..0000000
--- a/.github/workflows/dependabot-sync.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: dependabot-sync
-on:
- schedule:
- - cron: "0 0 * * 0" # every Sunday at midnight
- workflow_dispatch: # allows manual triggering
-
-permissions:
- contents: write
- pull-requests: write
-
-jobs:
- dependabot-sync:
- uses: charmbracelet/meta/.github/workflows/dependabot-sync.yml@main
- with:
- repo_name: ${{ github.event.repository.name }}
- secrets:
- gh_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
diff --git a/.github/workflows/lint-soft.yml b/.github/workflows/lint-soft.yml
new file mode 100644
index 0000000..87d1e1f
--- /dev/null
+++ b/.github/workflows/lint-soft.yml
@@ -0,0 +1,28 @@
+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
diff --git a/.github/workflows/lint-sync.yml b/.github/workflows/lint-sync.yml
deleted file mode 100644
index ecf8580..0000000
--- a/.github/workflows/lint-sync.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-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
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index a1d6d0e..f617a5a 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -3,6 +3,26 @@ on:
push:
pull_request:
+permissions:
+ contents: read
+ # Optional: allow read access to pull request. Use with `only-new-issues` option.
+ pull-requests: read
+
jobs:
- lint:
- uses: charmbracelet/meta/.github/workflows/lint.yml@main
+ 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
diff --git a/.golangci-soft.yml b/.golangci-soft.yml
new file mode 100644
index 0000000..82c337e
--- /dev/null
+++ b/.golangci-soft.yml
@@ -0,0 +1,39 @@
+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
+
+ # disable default linters, they are already enabled in .golangci.yml
+ disable:
+ - wrapcheck
+ - errcheck
+ - gosimple
+ - govet
+ - ineffassign
+ - staticcheck
+ - typecheck
diff --git a/.golangci.yml b/.golangci.yml
index c90f031..684d54b 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,22 +1,24 @@
-version: "2"
run:
tests: false
+
+issues:
+ include:
+ - EXC0001
+ - EXC0005
+ - EXC0011
+ - EXC0012
+ - EXC0013
+
+ max-issues-per-linter: 0
+ max-same-issues: 0
+
linters:
enable:
- bodyclose
- - exhaustive
- - goconst
- - godot
- - gomoddirectives
- - goprintffuncname
+ - goimports
- gosec
- - misspell
- - nakedret
- - nestif
- nilerr
- - noctx
- - nolintlint
- - prealloc
+ - predeclared
- revive
- rowserrcheck
- sqlclosecheck
@@ -24,24 +26,3 @@ linters:
- unconvert
- unparam
- whitespace
- - wrapcheck
- exclusions:
- rules:
- - text: '(slog|log)\.\w+'
- linters:
- - noctx
- generated: lax
- presets:
- - common-false-positives
- settings:
- exhaustive:
- default-signifies-exhaustive: true
-issues:
- max-issues-per-linter: 0
- max-same-issues: 0
-formatters:
- enable:
- - gofumpt
- - goimports
- exclusions:
- generated: lax
diff --git a/README.md b/README.md
index 80a2b67..a538089 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ The above example is running from a single shell script ([source](./examples/dem
## Tutorial
Gum provides highly configurable, ready-to-use utilities to help you write
-useful shell scripts and dotfile aliases with just a few lines of code.
+useful shell scripts and dotfiles aliases with just a few lines of code.
Let's build a simple script to help you write
[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary)
for your dotfiles.
@@ -68,9 +68,6 @@ brew install gum
# Arch Linux (btw)
pacman -S gum
-# Fedora or EPEL 10
-dnf install gum
-
# Nix
nix-env -iA nixpkgs.gum
@@ -116,19 +113,6 @@ sudo zypper install gum
-
-FreeBSD
-
-```bash
-# packages
-sudo pkg install gum
-
-# ports
-cd /usr/ports/devel/gum && sudo make install clean
-```
-
-
-
Or download it:
- [Packages][releases] are available in Debian, RPM, and Alpine formats
@@ -267,7 +251,7 @@ gum confirm && rm file.txt || echo "File not removed"
Prompt the user to select a file from the file tree.
```bash
-$EDITOR $(gum file $HOME)
+EDITOR $(gum file $HOME)
```
@@ -460,12 +444,6 @@ gum filter < $HISTFILE --height 20
alias please="gum input --password | sudo -nS"
```
-## Contributing
-
-See [contributing][contribute].
-
-[contribute]: https://github.com/charmbracelet/gum/contribute
-
## Feedback
We’d love to hear your thoughts on this project. Feel free to drop us a note!
diff --git a/choose/choose.go b/choose/choose.go
index c6be614..6594676 100644
--- a/choose/choose.go
+++ b/choose/choose.go
@@ -18,7 +18,6 @@ import (
"github.com/charmbracelet/bubbles/paginator"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/charmbracelet/x/exp/ordered"
)
func defaultKeymap() keymap {
@@ -98,7 +97,6 @@ func (k keymap) ShortHelp() []key.Binding {
type model struct {
height int
- padding []int
cursor string
selectedPrefix string
unselectedPrefix string
@@ -159,10 +157,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.paginator.PrevPage()
}
case key.Matches(msg, km.Right):
- m.index = ordered.Clamp(m.index+m.height, 0, len(m.items)-1)
+ m.index = clamp(m.index+m.height, 0, len(m.items)-1)
m.paginator.NextPage()
case key.Matches(msg, km.Left):
- m.index = ordered.Clamp(m.index-m.height, 0, len(m.items)-1)
+ m.index = clamp(m.index-m.height, 0, len(m.items)-1)
m.paginator.PrevPage()
case key.Matches(msg, km.End):
m.index = len(m.items) - 1
@@ -279,11 +277,18 @@ func (m model) View() string {
}
parts = append(parts, s.String())
if m.showHelp {
- parts = append(parts, "", m.help.View(m.keymap))
+ parts = append(parts, m.help.View(m.keymap))
}
- view := lipgloss.JoinVertical(lipgloss.Left, parts...)
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(view)
+ return lipgloss.JoinVertical(lipgloss.Left, parts...)
+}
+
+func clamp(x, low, high int) int {
+ if x < low {
+ return low
+ }
+ if x > high {
+ return high
+ }
+ return x
}
diff --git a/choose/command.go b/choose/command.go
index 70b8a9f..47e3549 100644
--- a/choose/command.go
+++ b/choose/command.go
@@ -3,6 +3,7 @@ package choose
import (
"errors"
"fmt"
+ "maps"
"os"
"slices"
"sort"
@@ -14,7 +15,6 @@ import (
"github.com/charmbracelet/gum/internal/stdin"
"github.com/charmbracelet/gum/internal/timeout"
"github.com/charmbracelet/gum/internal/tty"
- "github.com/charmbracelet/gum/style"
"github.com/charmbracelet/lipgloss"
)
@@ -38,8 +38,6 @@ func (o Options) Run() error {
// normalize options into a map
options := map[string]string{}
- // keep the labels in the user-provided order
- var labels []string //nolint:prealloc
for _, opt := range o.Options {
if o.LabelDelimiter == "" {
options[opt] = opt
@@ -49,11 +47,10 @@ func (o Options) Run() error {
if !ok {
return fmt.Errorf("invalid option format: %q", opt)
}
- labels = append(labels, label)
options[label] = value
}
if o.LabelDelimiter != "" {
- o.Options = labels
+ o.Options = slices.Collect(maps.Keys(options))
}
if o.SelectIfOne && len(o.Options) == 1 {
@@ -108,7 +105,6 @@ func (o Options) Run() error {
// Use the pagination model to display the current and total number of
// pages.
- top, right, bottom, left := style.ParsePadding(o.Padding)
pager := paginator.New()
pager.SetTotalPages((len(items) + o.Height - 1) / o.Height)
pager.PerPage = o.Height
@@ -130,7 +126,6 @@ func (o Options) Run() error {
index: startingIndex,
currentOrder: currentOrder,
height: o.Height,
- padding: []int{top, right, bottom, left},
cursor: o.Cursor,
header: o.Header,
selectedPrefix: o.SelectedPrefix,
diff --git a/choose/options.go b/choose/options.go
index abfca22..e5ea6b2 100644
--- a/choose/options.go
+++ b/choose/options.go
@@ -15,18 +15,17 @@ type Options struct {
Height int `help:"Height of the list" default:"10" env:"GUM_CHOOSE_HEIGHT"`
Cursor string `help:"Prefix to show on item that corresponds to the cursor position" default:"> " env:"GUM_CHOOSE_CURSOR"`
ShowHelp bool `help:"Show help keybinds" default:"true" negatable:"" env:"GUM_CHOOSE_SHOW_HELP"`
- Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_CHOOSE_TIMEOUT"` // including timeout command options [Timeout,...]
+ Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_CCHOOSE_TIMEOUT"` // including timeout command options [Timeout,...]
Header string `help:"Header value" default:"Choose:" env:"GUM_CHOOSE_HEADER"`
CursorPrefix string `help:"Prefix to show on the cursor item (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_CURSOR_PREFIX"`
SelectedPrefix string `help:"Prefix to show on selected items (hidden if limit is 1)" default:"✓ " env:"GUM_CHOOSE_SELECTED_PREFIX"`
UnselectedPrefix string `help:"Prefix to show on unselected items (hidden if limit is 1)" default:"• " env:"GUM_CHOOSE_UNSELECTED_PREFIX"`
- Selected []string `help:"Options that should start as selected (selects all if given *)" default:"" env:"GUM_CHOOSE_SELECTED"`
+ Selected []string `help:"Options that should start as selected (selects all if given '*')" default:"" env:"GUM_CHOOSE_SELECTED"`
SelectIfOne bool `help:"Select the given option if there is only one" group:"Selection"`
InputDelimiter string `help:"Option delimiter when reading from STDIN" default:"\n" env:"GUM_CHOOSE_INPUT_DELIMITER"`
OutputDelimiter string `help:"Option delimiter when writing to STDOUT" default:"\n" env:"GUM_CHOOSE_OUTPUT_DELIMITER"`
LabelDelimiter string `help:"Allows to set a delimiter, so options can be set as label:value" default:"" env:"GUM_CHOOSE_LABEL_DELIMITER"`
StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_CHOOSE_STRIP_ANSI"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_CHOOSE_PADDING"`
CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_CURSOR_"`
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_CHOOSE_HEADER_"`
diff --git a/completion/bash.go b/completion/bash.go
index 33d309b..3064ec1 100644
--- a/completion/bash.go
+++ b/completion/bash.go
@@ -1,5 +1,3 @@
-// Package completion provides a bash completion generator for Kong
-// applications.
package completion
import (
@@ -630,7 +628,6 @@ func writeCmdAliases(buf io.StringWriter, cmd *kong.Node) {
writeString(buf, ` fi`)
writeString(buf, "\n")
}
-
func writeArgAliases(buf io.StringWriter, cmd *kong.Node) {
writeString(buf, " noun_aliases=()\n")
sort.Strings(cmd.Aliases)
diff --git a/completion/fish.go b/completion/fish.go
index 9fc80d2..8335356 100644
--- a/completion/fish.go
+++ b/completion/fish.go
@@ -79,7 +79,7 @@ func (f Fish) gen(buf io.StringWriter, cmd *kong.Node) {
_, _ = buf.WriteString(fmt.Sprintf(" -s %c", f.Short))
}
_, _ = buf.WriteString(fmt.Sprintf(" -l %s", f.Name))
- _, _ = buf.WriteString(fmt.Sprintf(" -d \"%s\"", f.Help))
+ _, _ = buf.WriteString(fmt.Sprintf(" -d '%s'", f.Help))
_, _ = buf.WriteString("\n")
}
_, _ = buf.WriteString("\n")
diff --git a/confirm/command.go b/confirm/command.go
index fc0a02b..ed5cf6e 100644
--- a/confirm/command.go
+++ b/confirm/command.go
@@ -1,7 +1,6 @@
package confirm
import (
- "context"
"fmt"
"os"
@@ -10,7 +9,6 @@ import (
"github.com/charmbracelet/gum/internal/exit"
"github.com/charmbracelet/gum/internal/stdin"
"github.com/charmbracelet/gum/internal/timeout"
- "github.com/charmbracelet/gum/style"
)
// Run provides a shell script interface for prompting a user to confirm an
@@ -29,7 +27,6 @@ func (o Options) Run() error {
ctx, cancel := timeout.Context(o.Timeout)
defer cancel()
- top, right, bottom, left := style.ParsePadding(o.Padding)
m := model{
affirmative: o.Affirmative,
negative: o.Negative,
@@ -43,17 +40,15 @@ func (o Options) Run() error {
selectedStyle: o.SelectedStyle.ToLipgloss(),
unselectedStyle: o.UnselectedStyle.ToLipgloss(),
promptStyle: o.PromptStyle.ToLipgloss(),
- padding: []int{top, right, bottom, left},
}
tm, err := tea.NewProgram(
m,
tea.WithOutput(os.Stderr),
tea.WithContext(ctx),
).Run()
- if err != nil && ctx.Err() != context.DeadlineExceeded {
+ if err != nil {
return fmt.Errorf("unable to confirm: %w", err)
}
- m = tm.(model)
if o.ShowOutput {
confirmationText := m.negative
@@ -63,6 +58,7 @@ func (o Options) Run() error {
fmt.Println(m.prompt, confirmationText)
}
+ m = tm.(model)
if m.confirmation {
return nil
}
diff --git a/confirm/confirm.go b/confirm/confirm.go
index ac35c39..c32ade9 100644
--- a/confirm/confirm.go
+++ b/confirm/confirm.go
@@ -91,7 +91,6 @@ type model struct {
promptStyle lipgloss.Style
selectedStyle lipgloss.Style
unselectedStyle lipgloss.Style
- padding []int
}
func (m model) Init() tea.Cmd { return nil }
@@ -150,19 +149,18 @@ func (m model) View() string {
neg = ""
}
- parts := []string{
- m.promptStyle.Render(m.prompt) + "\n",
- lipgloss.JoinHorizontal(lipgloss.Left, aff, neg),
- }
-
if m.showHelp {
- parts = append(parts, "", m.help.View(m.keys))
+ return lipgloss.JoinVertical(
+ lipgloss.Left,
+ m.promptStyle.Render(m.prompt)+"\n",
+ lipgloss.JoinHorizontal(lipgloss.Left, aff, neg),
+ "\n"+m.help.View(m.keys),
+ )
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(lipgloss.JoinVertical(
- lipgloss.Left,
- parts...,
- ))
+ return lipgloss.JoinVertical(
+ lipgloss.Left,
+ m.promptStyle.Render(m.prompt)+"\n",
+ lipgloss.JoinHorizontal(lipgloss.Left, aff, neg),
+ )
}
diff --git a/confirm/options.go b/confirm/options.go
index 9740885..b38d7e0 100644
--- a/confirm/options.go
+++ b/confirm/options.go
@@ -21,5 +21,4 @@ type Options struct {
UnselectedStyle style.Styles `embed:"" prefix:"unselected." help:"The style of the unselected action" set:"defaultBackground=235" set:"defaultForeground=254" set:"defaultPadding=0 3" set:"defaultMargin=0 1" envprefix:"GUM_CONFIRM_UNSELECTED_"`
ShowHelp bool `help:"Show help key binds" negatable:"" default:"true" env:"GUM_CONFIRM_SHOW_HELP"`
Timeout time.Duration `help:"Timeout until confirm returns selected value or default if provided" default:"0s" env:"GUM_CONFIRM_TIMEOUT"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_CONFIRM_PADDING"`
}
diff --git a/cursor/cursor.go b/cursor/cursor.go
index 3c49849..aa49c05 100644
--- a/cursor/cursor.go
+++ b/cursor/cursor.go
@@ -1,4 +1,3 @@
-// Package cursor provides cursor modes.
package cursor
import (
diff --git a/default.nix b/default.nix
index 511568f..5c14976 100644
--- a/default.nix
+++ b/default.nix
@@ -2,11 +2,11 @@
pkgs.buildGoModule rec {
pname = "gum";
- version = "0.15.2";
+ version = "0.15.0";
src = ./.;
- vendorHash = "sha256-TK2Fc4bTkiSpyYrg4dJOzamEnii03P7kyHZdah9izqY=";
+ vendorHash = "sha256-i/KBe41ufYA+tqnB5LCC1geIc2Jnh97JLXcXfBgxdM4=";
ldflags = [ "-s" "-w" "-X=main.Version=${version}" ];
}
diff --git a/file/command.go b/file/command.go
index b7cc546..89472dd 100644
--- a/file/command.go
+++ b/file/command.go
@@ -10,7 +10,6 @@ import (
"github.com/charmbracelet/bubbles/help"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/internal/timeout"
- "github.com/charmbracelet/gum/style"
)
// Run is the interface to picking a file.
@@ -31,7 +30,7 @@ func (o Options) Run() error {
fp := filepicker.New()
fp.CurrentDirectory = path
fp.Path = path
- fp.SetHeight(o.Height)
+ fp.Height = o.Height
fp.AutoHeight = o.Height == 0
fp.Cursor = o.Cursor
fp.DirAllowed = o.Directory
@@ -47,10 +46,8 @@ func (o Options) Run() error {
fp.Styles.Permission = o.PermissionsStyle.ToLipgloss()
fp.Styles.Selected = o.SelectedStyle.ToLipgloss()
fp.Styles.FileSize = o.FileSizeStyle.ToLipgloss()
- top, right, bottom, left := style.ParsePadding(o.Padding)
m := model{
filepicker: fp,
- padding: []int{top, right, bottom, left},
showHelp: o.ShowHelp,
help: help.New(),
keymap: defaultKeymap(),
diff --git a/file/file.go b/file/file.go
index 33c8233..a9878af 100644
--- a/file/file.go
+++ b/file/file.go
@@ -59,7 +59,6 @@ type model struct {
selectedPath string
quitting bool
showHelp bool
- padding []int
help help.Model
keymap keymap
}
@@ -69,11 +68,9 @@ func (m model) Init() tea.Cmd { return m.filepicker.Init() }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
- height := msg.Height - m.padding[0] - m.padding[2]
if m.showHelp {
- height -= lipgloss.Height(m.helpView())
+ m.filepicker.Height -= lipgloss.Height(m.helpView())
}
- m.filepicker.SetHeight(height)
case tea.KeyMsg:
switch {
case key.Matches(msg, keyAbort):
@@ -106,12 +103,7 @@ func (m model) View() string {
if m.showHelp {
parts = append(parts, m.helpView())
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(lipgloss.JoinVertical(
- lipgloss.Left,
- parts...,
- ))
+ return lipgloss.JoinVertical(lipgloss.Left, parts...)
}
func (m model) helpView() string {
diff --git a/file/options.go b/file/options.go
index 61c9ced..72bfb8f 100644
--- a/file/options.go
+++ b/file/options.go
@@ -30,5 +30,4 @@ type Options struct {
SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style to use for the selected item" set:"defaultBold=true" set:"defaultForeground=212" envprefix:"GUM_FILE_SELECTED_"` //nolint:staticcheck
FileSizeStyle style.Styles `embed:"" prefix:"file-size." help:"The style to use for file sizes" set:"defaultWidth=8" set:"defaultAlign=right" set:"defaultForeground=240" envprefix:"GUM_FILE_FILE_SIZE_"` //nolint:staticcheck
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_FILE_HEADER_"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_FILE_PADDING"`
}
diff --git a/filter/command.go b/filter/command.go
index 6c9b2a3..4185100 100644
--- a/filter/command.go
+++ b/filter/command.go
@@ -15,7 +15,6 @@ import (
"github.com/charmbracelet/gum/internal/stdin"
"github.com/charmbracelet/gum/internal/timeout"
"github.com/charmbracelet/gum/internal/tty"
- "github.com/charmbracelet/gum/style"
"github.com/charmbracelet/x/ansi"
"github.com/sahilm/fuzzy"
)
@@ -95,7 +94,7 @@ func (o Options) Run() error {
km.ToggleAndNext.SetEnabled(true)
km.ToggleAll.SetEnabled(true)
}
- top, right, bottom, left := style.ParsePadding(o.Padding)
+
m := model{
choices: choices,
filteringChoices: filteringChoices,
@@ -114,7 +113,6 @@ func (o Options) Run() error {
textStyle: o.TextStyle.ToLipgloss(),
cursorTextStyle: o.CursorTextStyle.ToLipgloss(),
height: o.Height,
- padding: []int{top, right, bottom, left},
selected: make(map[string]struct{}),
limit: o.Limit,
reverse: o.Reverse,
diff --git a/filter/filter.go b/filter/filter.go
index 5e433cd..d321bcb 100644
--- a/filter/filter.go
+++ b/filter/filter.go
@@ -19,7 +19,6 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
- "github.com/charmbracelet/x/exp/ordered"
"github.com/rivo/uniseg"
"github.com/sahilm/fuzzy"
)
@@ -138,7 +137,6 @@ type model struct {
selectedPrefix string
unselectedPrefix string
height int
- padding []int
quitting bool
headerStyle lipgloss.Style
matchStyle lipgloss.Style
@@ -232,35 +230,33 @@ func (m model) View() string {
m.viewport.SetContent(s.String())
+ help := ""
+ if m.showHelp {
+ help = m.helpView()
+ }
+
// View the input and the filtered choices
header := m.headerStyle.Render(m.header)
if m.reverse {
- view := m.viewport.View()
- if m.header != "" {
- view += "\n" + header
- }
- view += "\n" + m.textinput.View()
+ view := m.viewport.View() + "\n" + m.textinput.View()
if m.showHelp {
- view += m.helpView()
+ view += help
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(view)
+ if m.header != "" {
+ return lipgloss.JoinVertical(lipgloss.Left, view, header)
+ }
+
+ return view
}
view := m.textinput.View() + "\n" + m.viewport.View()
if m.showHelp {
- view += m.helpView()
+ view += help
}
if m.header != "" {
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(header + "\n" + view)
+ return lipgloss.JoinVertical(lipgloss.Left, header, view)
}
-
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(view)
+ return view
}
func (m model) helpView() string {
@@ -283,11 +279,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.showHelp {
m.viewport.Height = m.viewport.Height - lipgloss.Height(m.helpView())
}
- m.viewport.Height = m.viewport.Height - m.padding[0] - m.padding[2]
- m.viewport.Width = msg.Width - m.padding[1] - m.padding[3]
- m.textinput.Width = msg.Width - m.padding[1] - m.padding[3]
+ m.viewport.Width = msg.Width
if m.reverse {
- m.viewport.YOffset = ordered.Clamp(len(m.matches)-m.viewport.Height, 0, len(m.matches))
+ m.viewport.YOffset = clamp(0, len(m.matches), len(m.matches)-m.viewport.Height)
}
case tea.KeyMsg:
km := m.keymap
@@ -379,7 +373,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// it remains at a constant position relative to the cursor.
if m.reverse {
maxYOffset := max(0, len(m.matches)-m.viewport.Height)
- m.viewport.YOffset = ordered.Clamp(len(m.matches)-yOffsetFromBottom, 0, maxYOffset)
+ m.viewport.YOffset = clamp(0, maxYOffset, len(m.matches)-yOffsetFromBottom)
}
}
}
@@ -393,7 +387,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// It's possible that filtering items have caused fewer matches. So, ensure
// that the selected index is within the bounds of the number of matches.
- m.cursor = ordered.Clamp(m.cursor, 0, len(m.matches)-1)
+ m.cursor = clamp(0, len(m.matches)-1, m.cursor)
return m, tea.Batch(cmd, icmd)
}
@@ -404,7 +398,7 @@ func (m *model) CursorUp() {
if m.reverse { //nolint:nestif
m.cursor = (m.cursor + 1) % len(m.matches)
if len(m.matches)-m.cursor <= m.viewport.YOffset {
- m.viewport.ScrollUp(1)
+ m.viewport.LineUp(1)
}
if len(m.matches)-m.cursor > m.viewport.Height+m.viewport.YOffset {
m.viewport.SetYOffset(len(m.matches) - m.viewport.Height)
@@ -412,7 +406,7 @@ func (m *model) CursorUp() {
} else {
m.cursor = (m.cursor - 1 + len(m.matches)) % len(m.matches)
if m.cursor < m.viewport.YOffset {
- m.viewport.ScrollUp(1)
+ m.viewport.LineUp(1)
}
if m.cursor >= m.viewport.YOffset+m.viewport.Height {
m.viewport.SetYOffset(len(m.matches) - m.viewport.Height)
@@ -427,7 +421,7 @@ func (m *model) CursorDown() {
if m.reverse { //nolint:nestif
m.cursor = (m.cursor - 1 + len(m.matches)) % len(m.matches)
if len(m.matches)-m.cursor > m.viewport.Height+m.viewport.YOffset {
- m.viewport.ScrollDown(1)
+ m.viewport.LineDown(1)
}
if len(m.matches)-m.cursor <= m.viewport.YOffset {
m.viewport.GotoTop()
@@ -435,7 +429,7 @@ func (m *model) CursorDown() {
} else {
m.cursor = (m.cursor + 1) % len(m.matches)
if m.cursor >= m.viewport.YOffset+m.viewport.Height {
- m.viewport.ScrollDown(1)
+ m.viewport.LineDown(1)
}
if m.cursor < m.viewport.YOffset {
m.viewport.GotoTop()
@@ -504,6 +498,16 @@ func exactMatches(search string, choices []string) []fuzzy.Match {
return matches
}
+func clamp(low, high, val int) int {
+ if val < low {
+ return low
+ }
+ if val > high {
+ return high
+ }
+ return val
+}
+
func matchedRanges(in []int) [][2]int {
if len(in) == 0 {
return [][2]int{}
diff --git a/filter/options.go b/filter/options.go
index 26eb3ea..07c50ce 100644
--- a/filter/options.go
+++ b/filter/options.go
@@ -15,7 +15,7 @@ type Options struct {
Limit int `help:"Maximum number of options to pick" default:"1" group:"Selection"`
NoLimit bool `help:"Pick unlimited number of options (ignores limit)" group:"Selection"`
SelectIfOne bool `help:"Select the given option if there is only one" group:"Selection"`
- Selected []string `help:"Options that should start as selected (selects all if given *)" default:"" env:"GUM_FILTER_SELECTED"`
+ Selected []string `help:"Options that should start as selected (selects all if given '*')" default:"" env:"GUM_FILTER_SELECTED"`
ShowHelp bool `help:"Show help keybinds" default:"true" negatable:"" env:"GUM_FILTER_SHOW_HELP"`
Strict bool `help:"Only returns if anything matched. Otherwise return Filter" negatable:"" default:"true" group:"Selection"`
SelectedPrefix string `help:"Character to indicate selected items (hidden if limit is 1)" default:" ◉ " env:"GUM_FILTER_SELECTED_PREFIX"`
@@ -41,7 +41,6 @@ type Options struct {
InputDelimiter string `help:"Option delimiter when reading from STDIN" default:"\n" env:"GUM_FILTER_INPUT_DELIMITER"`
OutputDelimiter string `help:"Option delimiter when writing to STDOUT" default:"\n" env:"GUM_FILTER_OUTPUT_DELIMITER"`
StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_FILTER_STRIP_ANSI"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_FILTER_PADDING"`
// Deprecated: use [FuzzySort]. This will be removed at some point.
Sort bool `help:"Sort fuzzy results by their scores" default:"true" env:"GUM_FILTER_FUZZY_SORT" negatable:"" hidden:""`
diff --git a/go.mod b/go.mod
index 55e2352..49a2839 100644
--- a/go.mod
+++ b/go.mod
@@ -1,26 +1,24 @@
module github.com/charmbracelet/gum
-go 1.24.2
+go 1.23.0
require (
- github.com/Masterminds/semver/v3 v3.4.0
- github.com/alecthomas/kong v1.14.0
+ github.com/Masterminds/semver/v3 v3.3.1
+ github.com/alecthomas/kong v1.6.1
github.com/alecthomas/mango-kong v0.1.0
- github.com/charmbracelet/bubbles v1.0.0
- github.com/charmbracelet/bubbletea v1.3.10
- github.com/charmbracelet/glamour v0.10.0
- github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
- github.com/charmbracelet/log v0.4.2
- github.com/charmbracelet/x/ansi v0.11.6
- github.com/charmbracelet/x/editor v0.2.0
- github.com/charmbracelet/x/exp/ordered v0.1.0
- github.com/charmbracelet/x/term v0.2.2
- github.com/charmbracelet/x/xpty v0.1.3
+ github.com/charmbracelet/bubbles v0.20.0
+ github.com/charmbracelet/bubbletea v1.2.5-0.20241207142916-e0515bc22ad1
+ github.com/charmbracelet/glamour v0.8.0
+ github.com/charmbracelet/lipgloss v1.0.1-0.20250110214317-ecc1bd014d51
+ github.com/charmbracelet/log v0.4.0
+ github.com/charmbracelet/x/ansi v0.8.0
+ github.com/charmbracelet/x/editor v0.1.0
+ github.com/charmbracelet/x/term v0.2.1
github.com/muesli/roff v0.1.0
- github.com/muesli/termenv v0.16.0
+ github.com/muesli/termenv v0.15.3-0.20241211131612-0d230cb6eb15
github.com/rivo/uniseg v0.4.7
github.com/sahilm/fuzzy v0.1.1
- golang.org/x/text v0.34.0
+ golang.org/x/text v0.21.0
)
require (
@@ -28,35 +26,25 @@ require (
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
- github.com/charmbracelet/colorprofile v0.4.1 // indirect
- github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
- github.com/charmbracelet/x/conpty v0.1.1 // indirect
- github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 // indirect
- github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
- github.com/charmbracelet/x/termios v0.1.1 // indirect
- github.com/clipperhouse/displaywidth v0.9.0 // indirect
- github.com/clipperhouse/stringish v0.1.1 // indirect
- github.com/clipperhouse/uax29/v2 v2.5.0 // indirect
- github.com/creack/pty v1.1.24 // 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
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
- github.com/lucasb-eyer/go-colorful v1.3.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-localereader v0.0.1 // indirect
- github.com/mattn/go-runewidth v0.0.19 // 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/mango v0.2.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
- github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
- github.com/yuin/goldmark v1.7.8 // indirect
- github.com/yuin/goldmark-emoji v1.0.5 // indirect
+ github.com/yuin/goldmark v1.7.4 // indirect
+ github.com/yuin/goldmark-emoji v1.0.4 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
- golang.org/x/net v0.40.0 // indirect
- golang.org/x/sys v0.38.0 // indirect
- golang.org/x/term v0.32.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/term v0.27.0 // indirect
)
diff --git a/go.sum b/go.sum
index c3d39b7..7b3c806 100644
--- a/go.sum
+++ b/go.sum
@@ -1,67 +1,43 @@
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
-github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
-github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
+github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
-github.com/alecthomas/kong v1.14.0 h1:gFgEUZWu2ZmZ+UhyZ1bDhuutbKN1nTtJTwh19Wsn21s=
-github.com/alecthomas/kong v1.14.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
+github.com/alecthomas/kong v1.6.1 h1:/7bVimARU3uxPD0hbryPE8qWrS3Oz3kPQoxA/H2NKG8=
+github.com/alecthomas/kong v1.6.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/mango-kong v0.1.0 h1:iFVfP1k1K4qpml3JUQmD5I8MCQYfIvsD9mRdrw7jJC4=
github.com/alecthomas/mango-kong v0.1.0/go.mod h1:t+TYVdsONUolf/BwVcm+15eqcdAj15h4Qe9MMFAwwT4=
-github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
-github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
+github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
-github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
-github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
+github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
+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 v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=
-github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E=
-github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
-github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
-github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
-github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
-github.com/charmbracelet/glamour v0.10.0 h1:MtZvfwsYCx8jEPFJm3rIBFIMZUfUJ765oX8V6kXldcY=
-github.com/charmbracelet/glamour v0.10.0/go.mod h1:f+uf+I/ChNmqo087elLnVdCiVgjSKWuXa/l6NU2ndYk=
-github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE=
-github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA=
-github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
-github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
-github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
-github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
-github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
-github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
-github.com/charmbracelet/x/conpty v0.1.1 h1:s1bUxjoi7EpqiXysVtC+a8RrvPPNcNvAjfi4jxsAuEs=
-github.com/charmbracelet/x/conpty v0.1.1/go.mod h1:OmtR77VODEFbiTzGE9G1XiRJAga6011PIm4u5fTNZpk=
-github.com/charmbracelet/x/editor v0.2.0 h1:7XLUKtaRaB8jN7bWU2p2UChiySyaAuIfYiIRg8gGWwk=
-github.com/charmbracelet/x/editor v0.2.0/go.mod h1:p3oQ28TSL3YPd+GKJ1fHWcp+7bVGpedHpXmo0D6t1dY=
-github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA=
-github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
-github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
-github.com/charmbracelet/x/exp/ordered v0.1.0 h1:55/qLwjIh0gL0Vni+QAWk7T/qRVP6sBf+2agPBgnOFE=
-github.com/charmbracelet/x/exp/ordered v0.1.0/go.mod h1:5UHwmG+is5THxMyCJHNPCn2/ecI07aKNrW+LcResjJ8=
-github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf h1:rLG0Yb6MQSDKdB52aGX55JT1oi0P0Kuaj7wi1bLUpnI=
-github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf/go.mod h1:B3UgsnsBZS/eX42BlaNiJkD1pPOUa+oF1IYC6Yd2CEU=
-github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
-github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
-github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
-github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
-github.com/charmbracelet/x/xpty v0.1.3 h1:eGSitii4suhzrISYH50ZfufV3v085BXQwIytcOdFSsw=
-github.com/charmbracelet/x/xpty v0.1.3/go.mod h1:poPYpWuLDBFCKmKLDnhBp51ATa0ooD8FhypRwEFtH3Y=
-github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA=
-github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA=
-github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
-github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
-github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
-github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
-github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
-github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
+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/bubbletea v1.2.5-0.20241207142916-e0515bc22ad1 h1:osd3dk14DEriOrqJBWzeDE9eN2Yd00BkKzFAiLXxkS8=
+github.com/charmbracelet/bubbletea v1.2.5-0.20241207142916-e0515bc22ad1/go.mod h1:Hbk5+oE4a7cDyjfdPi4sHZ42aGTMYcmHnVDhsRswn7A=
+github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
+github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
+github.com/charmbracelet/lipgloss v1.0.1-0.20250110214317-ecc1bd014d51 h1:f+0mEkhorXNiBaHb4V9wyd364OH/aF7md7ZngkS+1gU=
+github.com/charmbracelet/lipgloss v1.0.1-0.20250110214317-ecc1bd014d51/go.mod h1:QRGthpgH59/perglqXZC8xPHqDGZ9BB45ChJCFEWEMI=
+github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
+github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
+github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
+github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
+github.com/charmbracelet/x/editor v0.1.0 h1:p69/dpvlwRTs9uYiPeAWruwsHqTFzHhTvQOd/WVSX98=
+github.com/charmbracelet/x/editor v0.1.0/go.mod h1:oivrEbcP/AYt/Hpvk5pwDXXrQ933gQS6UzL6fxqAGSA=
+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/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
+github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
@@ -78,15 +54,15 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
-github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
-github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+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=
@@ -99,8 +75,8 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
-github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
-github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
+github.com/muesli/termenv v0.15.3-0.20241211131612-0d230cb6eb15 h1:XGrI/sVwKFHXvDVSGfan37w1AFt14RLDqBqY0ThTgk0=
+github.com/muesli/termenv v0.15.3-0.20241211131612-0d230cb6eb15/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -109,26 +85,26 @@ 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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
-github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
-github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
-github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
-github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC4cIk=
-github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
+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.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90=
+github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
-golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
-golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
-golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
-golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
-golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
-golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/input/command.go b/input/command.go
index 0900d8d..7d96e72 100644
--- a/input/command.go
+++ b/input/command.go
@@ -11,7 +11,6 @@ import (
"github.com/charmbracelet/gum/cursor"
"github.com/charmbracelet/gum/internal/stdin"
"github.com/charmbracelet/gum/internal/timeout"
- "github.com/charmbracelet/gum/style"
)
// Run provides a shell script interface for the text input bubble.
@@ -44,12 +43,10 @@ func (o Options) Run() error {
i.EchoCharacter = '•'
}
- top, right, bottom, left := style.ParsePadding(o.Padding)
m := model{
textinput: i,
header: o.Header,
headerStyle: o.HeaderStyle.ToLipgloss(),
- padding: []int{top, right, bottom, left},
autoWidth: o.Width < 1,
showHelp: o.ShowHelp,
help: help.New(),
diff --git a/input/input.go b/input/input.go
index f63ac6a..505b052 100644
--- a/input/input.go
+++ b/input/input.go
@@ -38,7 +38,6 @@ func (k keymap) ShortHelp() []key.Binding {
type model struct {
autoWidth bool
header string
- padding []int
headerStyle lipgloss.Style
textinput textinput.Model
quitting bool
@@ -54,30 +53,27 @@ func (m model) View() string {
if m.quitting {
return ""
}
- var parts []string
if m.header != "" {
- parts = append(parts, m.headerStyle.Render(m.header))
+ header := m.headerStyle.Render(m.header)
+ return lipgloss.JoinVertical(lipgloss.Left, header, m.textinput.View())
}
- parts = append(parts, m.textinput.View())
- if m.showHelp {
- parts = append(parts, "", m.help.View(m.keymap))
+ if !m.showHelp {
+ return m.textinput.View()
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(lipgloss.JoinVertical(
- lipgloss.Top,
- parts...,
- ))
+ return lipgloss.JoinVertical(
+ lipgloss.Top,
+ m.textinput.View(),
+ "",
+ m.help.View(m.keymap),
+ )
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
if m.autoWidth {
- m.textinput.Width = msg.Width - 1 -
- lipgloss.Width(m.textinput.Prompt) -
- m.padding[1] - m.padding[3]
+ m.textinput.Width = msg.Width - lipgloss.Width(m.textinput.Prompt) - 1
}
case tea.KeyMsg:
switch msg.String() {
diff --git a/input/options.go b/input/options.go
index 57cbf53..7463adb 100644
--- a/input/options.go
+++ b/input/options.go
@@ -23,5 +23,4 @@ type Options struct {
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=240" envprefix:"GUM_INPUT_HEADER_"`
Timeout time.Duration `help:"Timeout until input aborts" default:"0s" env:"GUM_INPUT_TIMEOUT"`
StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_INPUT_STRIP_ANSI"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_INPUT_PADDING"`
}
diff --git a/internal/decode/align.go b/internal/decode/align.go
index 555f13c..813bcdd 100644
--- a/internal/decode/align.go
+++ b/internal/decode/align.go
@@ -1,4 +1,3 @@
-// Package decode position strings to lipgloss.
package decode
import "github.com/charmbracelet/lipgloss"
diff --git a/internal/exit/exit.go b/internal/exit/exit.go
index f523efc..c4f3387 100644
--- a/internal/exit/exit.go
+++ b/internal/exit/exit.go
@@ -1,7 +1,8 @@
-// Package exit code implementation.
package exit
-import "strconv"
+import (
+ "strconv"
+)
// StatusTimeout is the exit code for timed out commands.
const StatusTimeout = 124
diff --git a/internal/files/files.go b/internal/files/files.go
index d1cd19e..51e6950 100644
--- a/internal/files/files.go
+++ b/internal/files/files.go
@@ -1,4 +1,3 @@
-// Package files handles files.
package files
import (
@@ -19,6 +18,7 @@ func List() []string {
files = append(files, path)
return nil
})
+
if err != nil {
return []string{}
}
diff --git a/internal/log/log.go b/internal/log/log.go
new file mode 100644
index 0000000..2a9f9a9
--- /dev/null
+++ b/internal/log/log.go
@@ -0,0 +1,8 @@
+package log
+
+import "fmt"
+
+// Error prints an error message to the user.
+func Error(message string) {
+ fmt.Println("Error:", message)
+}
diff --git a/internal/stack/stack.go b/internal/stack/stack.go
new file mode 100644
index 0000000..b28fedb
--- /dev/null
+++ b/internal/stack/stack.go
@@ -0,0 +1,26 @@
+package stack
+
+// Stack is a stack interface for integers.
+type Stack struct {
+ Push func(int)
+ Pop func() int
+ Length func() int
+}
+
+// NewStack returns a new stack of integers.
+func NewStack() Stack {
+ slice := make([]int, 0)
+ return Stack{
+ Push: func(i int) {
+ slice = append(slice, i)
+ },
+ Pop: func() int {
+ res := slice[len(slice)-1]
+ slice = slice[:len(slice)-1]
+ return res
+ },
+ Length: func() int {
+ return len(slice)
+ },
+ }
+}
diff --git a/internal/stdin/stdin.go b/internal/stdin/stdin.go
index 2efdcfd..42b0162 100644
--- a/internal/stdin/stdin.go
+++ b/internal/stdin/stdin.go
@@ -1,4 +1,3 @@
-// Package stdin handles processing input from stdin.
package stdin
import (
diff --git a/internal/timeout/context.go b/internal/timeout/context.go
index ffd39e9..99eaf34 100644
--- a/internal/timeout/context.go
+++ b/internal/timeout/context.go
@@ -1,4 +1,3 @@
-// Package timeout handles context timeouts.
package timeout
import (
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
new file mode 100644
index 0000000..0e38598
--- /dev/null
+++ b/internal/utils/utils.go
@@ -0,0 +1,15 @@
+package utils
+
+import (
+ "strings"
+
+ "github.com/charmbracelet/lipgloss"
+)
+
+// LipglossPadding calculates how much padding a string is given by a style.
+func LipglossPadding(style lipgloss.Style) (int, int) {
+ render := style.Render(" ")
+ before := strings.Index(render, " ")
+ after := len(render) - len(" ") - before
+ return before, after
+}
diff --git a/log/command.go b/log/command.go
index 1240083..aff18cf 100644
--- a/log/command.go
+++ b/log/command.go
@@ -1,4 +1,3 @@
-// Package log the log command.
package log
import (
@@ -17,7 +16,7 @@ func (o Options) Run() error {
l := log.New(os.Stderr)
if o.File != "" {
- f, err := os.OpenFile(o.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm) //nolint:gosec
+ f, err := os.OpenFile(o.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
@@ -32,7 +31,7 @@ func (o Options) Run() error {
if o.MinLevel != "" {
lvl, err := log.ParseLevel(o.MinLevel)
if err != nil {
- return err //nolint:wrapcheck
+ return err
}
l.SetLevel(lvl)
}
diff --git a/log/options.go b/log/options.go
index 12949e3..73fbcec 100644
--- a/log/options.go
+++ b/log/options.go
@@ -18,7 +18,7 @@ type Options struct {
MinLevel string `help:"Minimal level to show" default:"" env:"GUM_LOG_LEVEL"`
- LevelStyle style.Styles `embed:"" prefix:"level." help:"The style of the level being used" set:"defaultBold=true" envprefix:"GUM_LOG_LEVEL_"`
+ LevelStyle style.Styles `embed:"" prefix:"level." help:"The style of the level being used" set:"defaultBold=true" envprefix:"GUM_LOG_LEVEL_"` //nolint:staticcheck
TimeStyle style.Styles `embed:"" prefix:"time." help:"The style of the time" envprefix:"GUM_LOG_TIME_"`
PrefixStyle style.Styles `embed:"" prefix:"prefix." help:"The style of the prefix" set:"defaultBold=true" set:"defaultFaint=true" envprefix:"GUM_LOG_PREFIX_"` //nolint:staticcheck
MessageStyle style.Styles `embed:"" prefix:"message." help:"The style of the message" envprefix:"GUM_LOG_MESSAGE_"`
diff --git a/main.go b/main.go
index a61916e..18fa9f0 100644
--- a/main.go
+++ b/main.go
@@ -1,4 +1,3 @@
-// Package main is Gum: a tool for glamorous shell scripts.
package main
import (
@@ -78,13 +77,13 @@ func main() {
if errors.As(err, &ex) {
os.Exit(int(ex))
}
- if errors.Is(err, tea.ErrInterrupted) {
- os.Exit(exit.StatusAborted)
- }
if errors.Is(err, tea.ErrProgramKilled) {
fmt.Fprintln(os.Stderr, "timed out")
os.Exit(exit.StatusTimeout)
}
+ if errors.Is(err, tea.ErrInterrupted) {
+ os.Exit(exit.StatusAborted)
+ }
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
diff --git a/man/command.go b/man/command.go
index 22f5bec..1d83dab 100644
--- a/man/command.go
+++ b/man/command.go
@@ -1,4 +1,3 @@
-// Package man the man command.
package man
import (
diff --git a/pager/pager.go b/pager/pager.go
index 324a314..6b38403 100644
--- a/pager/pager.go
+++ b/pager/pager.go
@@ -158,7 +158,7 @@ func (m *model) processText(msg tea.WindowSizeMsg) {
text.WriteString("\n")
}
} else {
- text.WriteString(textStyle.Render(line))
+ text.WriteString(textStyle.Render(line)) //nolint: gosec
text.WriteString("\n")
}
}
diff --git a/pager/search.go b/pager/search.go
index 134096c..be59a53 100644
--- a/pager/search.go
+++ b/pager/search.go
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/charmbracelet/bubbles/textinput"
+ "github.com/charmbracelet/gum/internal/utils"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi"
)
@@ -51,7 +52,7 @@ func (s *search) Execute(m *model) {
m.content = query.ReplaceAllString(m.content, m.matchStyle.Render("$1"))
// Recompile the regex to match the an replace the highlights.
- leftPad, _ := lipglossPadding(m.matchStyle)
+ leftPad, _ := utils.LipglossPadding(m.matchStyle)
matchingString := regexp.QuoteMeta(m.matchStyle.Render()[:leftPad]) + s.query.String() + regexp.QuoteMeta(m.matchStyle.Render()[leftPad:])
s.query, err = regexp.Compile(matchingString)
if err != nil {
@@ -81,7 +82,7 @@ func (s *search) NextMatch(m *model) {
return
}
- leftPad, rightPad := lipglossPadding(m.matchStyle)
+ leftPad, rightPad := utils.LipglossPadding(m.matchStyle)
s.matchIndex = (s.matchIndex + 1) % len(allMatches)
match := allMatches[s.matchIndex]
lhs := m.content[:match[0]]
@@ -124,7 +125,7 @@ func (s *search) PrevMatch(m *model) {
s.matchIndex = len(allMatches) - 1
}
- leftPad, rightPad := lipglossPadding(m.matchStyle)
+ leftPad, rightPad := utils.LipglossPadding(m.matchStyle)
match := allMatches[s.matchIndex]
lhs := m.content[:match[0]]
rhs := m.content[match[0]:]
@@ -158,18 +159,10 @@ func softWrapEm(str string, maxWidth int, softWrap bool) string {
text.WriteString("\n")
}
} else {
- text.WriteString(line)
+ text.WriteString(line) //nolint: gosec
text.WriteString("\n")
}
}
return text.String()
}
-
-// lipglossPadding calculates how much padding a string is given by a style.
-func lipglossPadding(style lipgloss.Style) (int, int) {
- render := style.Render(" ")
- before := strings.Index(render, " ")
- after := len(render) - len(" ") - before
- return before, after
-}
diff --git a/spin/command.go b/spin/command.go
index cff2797..02213f0 100644
--- a/spin/command.go
+++ b/spin/command.go
@@ -8,7 +8,6 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/internal/exit"
"github.com/charmbracelet/gum/internal/timeout"
- "github.com/charmbracelet/gum/style"
"github.com/charmbracelet/x/term"
)
@@ -21,7 +20,6 @@ func (o Options) Run() error {
s := spinner.New()
s.Style = o.SpinnerStyle.ToLipgloss()
s.Spinner = spinnerMap[o.Spinner]
- top, right, bottom, left := style.ParsePadding(o.Padding)
m := model{
spinner: s,
title: o.TitleStyle.ToLipgloss().Render(o.Title),
@@ -31,7 +29,6 @@ func (o Options) Run() error {
showStderr: (o.ShowOutput || o.ShowStderr) && isErrTTY,
showError: o.ShowError,
isTTY: isErrTTY,
- padding: []int{top, right, bottom, left},
}
ctx, cancel := timeout.Context(o.Timeout)
@@ -51,29 +48,22 @@ func (o Options) Run() error {
// If the command succeeds, and we are printing output and we are in a TTY then push the STDOUT we got to the actual
// STDOUT for piping or other things.
//nolint:nestif
- if m.err != nil {
- if _, err := fmt.Fprintf(os.Stderr, "%s\n", m.err.Error()); err != nil {
- return fmt.Errorf("failed to write to stdout: %w", err)
- }
- return exit.ErrExit(1)
- } else if m.status == 0 {
- var output string
- if o.ShowOutput || (o.ShowStdout && o.ShowStderr) {
- output = m.output
- } else if o.ShowStdout {
- output = m.stdout
- } else if o.ShowStderr {
- output = m.stderr
- }
- if output != "" {
- if _, err := os.Stdout.WriteString(output); err != nil {
- return fmt.Errorf("failed to write to stdout: %w", err)
+ if m.status == 0 {
+ if o.ShowOutput {
+ // BubbleTea writes the View() to stderr.
+ // If the program is being piped then put the accumulated output in stdout.
+ if !isOutTTY {
+ _, err := os.Stdout.WriteString(m.stdout)
+ if err != nil {
+ return fmt.Errorf("failed to write to stdout: %w", err)
+ }
}
}
} else if o.ShowError {
// Otherwise if we are showing errors and the command did not exit with a 0 status code then push all of the command
// output to the terminal. This way failed commands can be debugged.
- if _, err := os.Stdout.WriteString(m.output); err != nil {
+ _, err := os.Stdout.WriteString(m.output)
+ if err != nil {
return fmt.Errorf("failed to write to stdout: %w", err)
}
}
diff --git a/spin/options.go b/spin/options.go
index 702cc2a..5243eab 100644
--- a/spin/options.go
+++ b/spin/options.go
@@ -20,5 +20,4 @@ type Options struct {
TitleStyle style.Styles `embed:"" prefix:"title." envprefix:"GUM_SPIN_TITLE_"`
Align string `help:"Alignment of spinner with regard to the title" short:"a" type:"align" enum:"left,right" default:"left" env:"GUM_SPIN_ALIGN"`
Timeout time.Duration `help:"Timeout until spin command aborts" default:"0s" env:"GUM_SPIN_TIMEOUT"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_SPIN_PADDING"`
}
diff --git a/spin/pty.go b/spin/pty.go
deleted file mode 100644
index 9562434..0000000
--- a/spin/pty.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package spin
-
-import (
- "os"
-
- "github.com/charmbracelet/x/term"
- "github.com/charmbracelet/x/xpty"
-)
-
-func openPty(f *os.File) (pty xpty.Pty, err error) {
- width, height, err := term.GetSize(f.Fd())
- if err != nil {
- return nil, err //nolint:wrapcheck
- }
-
- pty, err = xpty.NewPty(width, height)
- if err != nil {
- return nil, err //nolint:wrapcheck
- }
-
- return pty, nil
-}
diff --git a/spin/spin.go b/spin/spin.go
index 6e41690..d675bab 100644
--- a/spin/spin.go
+++ b/spin/spin.go
@@ -15,25 +15,20 @@
package spin
import (
- "bytes"
- "context"
"io"
"os"
"os/exec"
- "runtime"
+ "strings"
"syscall"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/term"
- "github.com/charmbracelet/x/xpty"
)
type model struct {
spinner spinner.Model
title string
- padding []int
align string
command []string
quitting bool
@@ -45,19 +40,16 @@ type model struct {
showStdout bool
showStderr bool
showError bool
- err error
}
var (
- bothbuf bytes.Buffer
- outbuf bytes.Buffer
- errbuf bytes.Buffer
+ bothbuf strings.Builder
+ outbuf strings.Builder
+ errbuf strings.Builder
executing *exec.Cmd
)
-type errorMsg error
-
type finishCommandMsg struct {
stdout string
stderr string
@@ -72,52 +64,16 @@ func commandStart(command []string) tea.Cmd {
args = command[1:]
}
- executing = exec.CommandContext(context.Background(), command[0], args...) //nolint:gosec
- executing.Stdin = os.Stdin
-
- isTerminal := term.IsTerminal(os.Stdout.Fd())
-
- // NOTE(@andreynering): We had issues with Git Bash on Windows
- // when it comes to handling PTYs, so we're falling back to
- // to redirecting stdout/stderr as usual to avoid issues.
- //nolint:nestif
- if isTerminal && runtime.GOOS == "windows" {
+ executing = exec.Command(command[0], args...) //nolint:gosec
+ if term.IsTerminal(os.Stdout.Fd()) {
executing.Stdout = io.MultiWriter(&bothbuf, &outbuf)
executing.Stderr = io.MultiWriter(&bothbuf, &errbuf)
- _ = executing.Run()
- } else if isTerminal {
- stdoutPty, err := openPty(os.Stdout)
- if err != nil {
- return errorMsg(err)
- }
- defer stdoutPty.Close() //nolint:errcheck
-
- stderrPty, err := openPty(os.Stderr)
- if err != nil {
- return errorMsg(err)
- }
- defer stderrPty.Close() //nolint:errcheck
-
- if outUnixPty, isOutUnixPty := stdoutPty.(*xpty.UnixPty); isOutUnixPty {
- executing.Stdout = outUnixPty.Slave()
- }
- if errUnixPty, isErrUnixPty := stderrPty.(*xpty.UnixPty); isErrUnixPty {
- executing.Stderr = errUnixPty.Slave()
- }
-
- go io.Copy(io.MultiWriter(&bothbuf, &outbuf), stdoutPty) //nolint:errcheck
- go io.Copy(io.MultiWriter(&bothbuf, &errbuf), stderrPty) //nolint:errcheck
-
- if err = stdoutPty.Start(executing); err != nil {
- return errorMsg(err)
- }
- _ = xpty.WaitProcess(context.Background(), executing)
} else {
executing.Stdout = os.Stdout
executing.Stderr = os.Stderr
- _ = executing.Run()
}
-
+ executing.Stdin = os.Stdin
+ _ = executing.Run()
status := executing.ProcessState.ExitCode()
if status == -1 {
status = 1
@@ -147,10 +103,6 @@ func (m model) Init() tea.Cmd {
}
func (m model) View() string {
- if m.quitting {
- return ""
- }
-
var out string
if m.showStderr {
out += errbuf.String()
@@ -159,6 +111,10 @@ func (m model) View() string {
out += outbuf.String()
}
+ if m.quitting {
+ return out
+ }
+
if !m.isTTY {
return m.title
}
@@ -169,12 +125,11 @@ func (m model) View() string {
} else {
header = m.title + " " + m.spinner.View()
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(header, "", out)
+ return header + "\n" + out
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+ var cmd tea.Cmd
switch msg := msg.(type) {
case finishCommandMsg:
m.stdout = msg.stdout
@@ -188,13 +143,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "ctrl+c":
return m, commandAbort
}
- case errorMsg:
- m.err = msg
- m.quitting = true
- return m, tea.Quit
}
- var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}
diff --git a/style/lipgloss.go b/style/lipgloss.go
index 07ad0c8..9ba52a2 100644
--- a/style/lipgloss.go
+++ b/style/lipgloss.go
@@ -19,7 +19,7 @@ func (s Styles) ToLipgloss() lipgloss.Style {
Height(s.Height).
Width(s.Width).
Margin(parseMargin(s.Margin)).
- Padding(ParsePadding(s.Padding)).
+ Padding(parsePadding(s.Padding)).
Bold(s.Bold).
Faint(s.Faint).
Italic(s.Italic).
@@ -40,7 +40,7 @@ func (s StylesNotHidden) ToLipgloss() lipgloss.Style {
Height(s.Height).
Width(s.Width).
Margin(parseMargin(s.Margin)).
- Padding(ParsePadding(s.Padding)).
+ Padding(parsePadding(s.Padding)).
Bold(s.Bold).
Faint(s.Faint).
Italic(s.Italic).
diff --git a/style/spacing.go b/style/spacing.go
index 57ea7db..6b3fe26 100644
--- a/style/spacing.go
+++ b/style/spacing.go
@@ -5,15 +5,13 @@ import (
"strings"
)
-const (
- minTokens = 1
- halfTokens = 2
- maxTokens = 4
-)
+const minTokens = 1
+const halfTokens = 2
+const maxTokens = 4
-// ParsePadding parses 1 - 4 integers from a string and returns them in a top,
+// parsePadding parses 1 - 4 integers from a string and returns them in a top,
// right, bottom, left order for use in the lipgloss.Padding() method.
-func ParsePadding(s string) (int, int, int, int) {
+func parsePadding(s string) (int, int, int, int) {
var ints [maxTokens]int
tokens := strings.Split(s, " ")
@@ -48,4 +46,4 @@ func ParsePadding(s string) (int, int, int, int) {
// parseMargin is an alias for parsePadding since they involve the same logic
// to parse integers to the same format.
-var parseMargin = ParsePadding
+var parseMargin = parsePadding
diff --git a/table/command.go b/table/command.go
index 479cd93..ae52bbf 100644
--- a/table/command.go
+++ b/table/command.go
@@ -79,7 +79,6 @@ func (o Options) Run() error {
}
defaultStyles := table.DefaultStyles()
- top, right, bottom, left := style.ParsePadding(o.Padding)
styles := table.Styles{
Cell: defaultStyles.Cell.Inherit(o.CellStyle.ToLipgloss()),
@@ -134,7 +133,7 @@ func (o Options) Run() error {
table.WithStyles(styles),
}
if o.Height > 0 {
- opts = append(opts, table.WithHeight(o.Height-top-bottom))
+ opts = append(opts, table.WithHeight(o.Height))
}
table := table.New(opts...)
@@ -143,12 +142,10 @@ func (o Options) Run() error {
defer cancel()
m := model{
- table: table,
- showHelp: o.ShowHelp,
- hideCount: o.HideCount,
- help: help.New(),
- keymap: defaultKeymap(),
- padding: []int{top, right, bottom, left},
+ table: table,
+ showHelp: o.ShowHelp,
+ help: help.New(),
+ keymap: defaultKeymap(),
}
tm, err := tea.NewProgram(
m,
diff --git a/table/options.go b/table/options.go
index d7a241f..5949c92 100644
--- a/table/options.go
+++ b/table/options.go
@@ -16,7 +16,6 @@ type Options struct {
File string `short:"f" help:"file path" default:""`
Border string `short:"b" help:"border style" default:"rounded" enum:"rounded,thick,normal,hidden,double,none"`
ShowHelp bool `help:"Show help keybinds" default:"true" negatable:"" env:"GUM_TABLE_SHOW_HELP"`
- HideCount bool `help:"Hide item count on help keybinds" default:"false" negatable:"" env:"GUM_TABLE_HIDE_COUNT"`
LazyQuotes bool `help:"If LazyQuotes is true, a quote may appear in an unquoted field and a non-doubled quote may appear in a quoted field" default:"false" env:"GUM_TABLE_LAZY_QUOTES"`
FieldsPerRecord int `help:"Sets the number of expected fields per record" default:"0" env:"GUM_TABLE_FIELDS_PER_RECORD"`
@@ -26,5 +25,4 @@ type Options struct {
SelectedStyle style.Styles `embed:"" prefix:"selected." set:"defaultForeground=212" envprefix:"GUM_TABLE_SELECTED_"`
ReturnColumn int `short:"r" help:"Which column number should be returned instead of whole row as string. Default=0 returns whole Row" default:"0"`
Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_TABLE_TIMEOUT"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_TABLE_PADDING"`
}
diff --git a/table/table.go b/table/table.go
index c0d389f..cbbb213 100644
--- a/table/table.go
+++ b/table/table.go
@@ -15,14 +15,10 @@
package table
import (
- "fmt"
- "strconv"
-
"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
)
type keymap struct {
@@ -66,32 +62,16 @@ func defaultKeymap() keymap {
}
type model struct {
- table table.Model
- selected table.Row
- quitting bool
- showHelp bool
- hideCount bool
- help help.Model
- keymap keymap
- padding []int
+ table table.Model
+ selected table.Row
+ quitting bool
+ showHelp bool
+ help help.Model
+ keymap keymap
}
func (m model) Init() tea.Cmd { return nil }
-func (m model) countView() string {
- if m.hideCount {
- return ""
- }
-
- padding := strconv.Itoa(numLen(len(m.table.Rows())))
- return m.help.Styles.FullDesc.Render(fmt.Sprintf(
- "%"+padding+"d/%d%s",
- m.table.Cursor()+1,
- len(m.table.Rows()),
- m.help.ShortSeparator,
- ))
-}
-
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
@@ -122,21 +102,7 @@ func (m model) View() string {
}
s := m.table.View()
if m.showHelp {
- s += "\n" + m.countView() + m.help.View(m.keymap)
+ s += "\n" + m.help.View(m.keymap)
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(s)
-}
-
-func numLen(i int) int {
- if i == 0 {
- return 1
- }
- count := 0
- for i != 0 {
- i /= 10
- count++
- }
- return count
+ return s
}
diff --git a/version/command.go b/version/command.go
index f90177d..5102b34 100644
--- a/version/command.go
+++ b/version/command.go
@@ -1,4 +1,3 @@
-// Package version the version command.
package version
import (
diff --git a/write/command.go b/write/command.go
index 6a745fb..adc3c69 100644
--- a/write/command.go
+++ b/write/command.go
@@ -12,7 +12,6 @@ import (
"github.com/charmbracelet/gum/cursor"
"github.com/charmbracelet/gum/internal/stdin"
"github.com/charmbracelet/gum/internal/timeout"
- "github.com/charmbracelet/gum/style"
)
// Run provides a shell script interface for the text area bubble.
@@ -31,7 +30,6 @@ func (o Options) Run() error {
a.ShowLineNumbers = o.ShowLineNumbers
a.CharLimit = o.CharLimit
a.MaxHeight = o.MaxLines
- top, right, bottom, left := style.ParsePadding(o.Padding)
style := textarea.Style{
Base: o.BaseStyle.ToLipgloss(),
@@ -48,8 +46,8 @@ func (o Options) Run() error {
a.Cursor.Style = o.CursorStyle.ToLipgloss()
a.Cursor.SetMode(cursor.Modes[o.CursorMode])
- a.SetWidth(max(0, o.Width-left-right))
- a.SetHeight(max(0, o.Height-top-bottom))
+ a.SetWidth(o.Width)
+ a.SetHeight(o.Height)
a.SetValue(o.Value)
m := model{
@@ -60,7 +58,6 @@ func (o Options) Run() error {
help: help.New(),
showHelp: o.ShowHelp,
keymap: defaultKeymap(),
- padding: []int{top, right, bottom, left},
}
m.textarea.KeyMap.InsertNewline = m.keymap.InsertNewline
diff --git a/write/options.go b/write/options.go
index 63c7b0c..16653eb 100644
--- a/write/options.go
+++ b/write/options.go
@@ -32,5 +32,4 @@ type Options struct {
HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=240" envprefix:"GUM_WRITE_HEADER_"`
PlaceholderStyle style.Styles `embed:"" prefix:"placeholder." set:"defaultForeground=240" envprefix:"GUM_WRITE_PLACEHOLDER_"`
PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=7" envprefix:"GUM_WRITE_PROMPT_"`
- Padding string `help:"Padding" default:"${defaultPadding}" group:"Style Flags" env:"GUM_WRITE_PADDING"`
}
diff --git a/write/write.go b/write/write.go
index b7e65a3..978bf0d 100644
--- a/write/write.go
+++ b/write/write.go
@@ -77,7 +77,6 @@ type model struct {
showHelp bool
help help.Model
keymap keymap
- padding []int
}
func (m model) Init() tea.Cmd { return textarea.Blink }
@@ -95,21 +94,16 @@ func (m model) View() string {
}
parts = append(parts, m.textarea.View())
if m.showHelp {
- parts = append(parts, "", m.help.View(m.keymap))
+ parts = append(parts, m.help.View(m.keymap))
}
- return lipgloss.NewStyle().
- Padding(m.padding...).
- Render(lipgloss.JoinVertical(
- lipgloss.Left,
- parts...,
- ))
+ return lipgloss.JoinVertical(lipgloss.Left, parts...)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
if m.autoWidth {
- m.textarea.SetWidth(msg.Width - m.padding[1] - m.padding[3])
+ m.textarea.SetWidth(msg.Width)
}
case tea.FocusMsg, tea.BlurMsg:
var cmd tea.Cmd
@@ -137,7 +131,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.submitted = true
return m, tea.Quit
case key.Matches(msg, km.OpenInEditor):
- return m, createTempFile(m.textarea.Value(), m.textarea.Line()+1)
+ //nolint: gosec
+ return m, createTempFile(m.textarea.Value(), uint(m.textarea.Line())+1)
}
}
@@ -148,7 +143,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
type startEditorMsg struct {
path string
- lineno int
+ lineno uint
}
type editorFinishedMsg struct {
@@ -156,7 +151,7 @@ type editorFinishedMsg struct {
err error
}
-func createTempFile(content string, lineno int) tea.Cmd {
+func createTempFile(content string, lineno uint) tea.Cmd {
return func() tea.Msg {
f, err := os.CreateTemp("", "gum.*.md")
if err != nil {
@@ -174,7 +169,7 @@ func createTempFile(content string, lineno int) tea.Cmd {
}
}
-func openEditor(path string, lineno int) tea.Cmd {
+func openEditor(path string, lineno uint) tea.Cmd {
cb := func(err error) tea.Msg {
if err != nil {
return editorFinishedMsg{