Skip to content

textinput v1/v2: Wayland Pasting Can Sometimes Cause Unexpected Errors #960

@pjkaufman

Description

@pjkaufman

Describe the bug
When on Wayland, there is an issue where when you copy from say VSCode and then close VSCode and then try to paste into the textinput component for bubbletea, it just causes an error that says exit status 1. There is really no good context to go off of since the underlying paste err type is not exported.

Setup
Please complete the following information along with version numbers, if applicable.

  • OS Pop OS 24.04 (really any Wayland Linux OS will do the trick, this likely is Wayland specific)
  • Shell bash
  • Terminal Emulator Kitty and Ghostty
  • Terminal Multiplexer with and without Tmux
  • Locale en_US.UTF-8

To Reproduce

Setup the following main.go:

package main

import (
	"log"
	"strings"

	"charm.land/bubbles/v2/textinput"
	tea "charm.land/bubbletea/v2"
	"github.com/atotto/clipboard"
)

func main() {
	ti := textinput.New()
	ti.SetWidth(20)
	ti.CharLimit = 200
	ti.Placeholder = "Section break"
	ti.Focus()

	var model = simpleModel{
		input: ti,
	}

	p := tea.NewProgram(&model)
	finalModel, err := p.Run()
	if err != nil {
		log.Fatal(err)
	}

	model, _ = finalModel.(simpleModel)
	if model.Err != nil {
		log.Fatalf("Something went wrong while running the TUI: %s\n", model.Err)
	}
}

type simpleModel struct {
	ready  bool
	input  textinput.Model
	pasted string
	Err    error
}

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

func (m simpleModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	if m.Err != nil {
		return m, tea.Quit
	}

	// general logic for handling keys here
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "ctrl+c":

			return m, tea.Quit
		case "ctrl+v":
			pasted, err := clipboard.ReadAll()
			if err == nil { // we are just using the err here to see if we got something from the clipboard to set the pasted value...
				m.pasted = pasted
			}
		}
	case tea.WindowSizeMsg:
		m.ready = true
	case error:
		m.Err = msg

		return m, tea.Quit
	}

	// we will do update last to make sure we can try to capture paste events before things crash, but it doesn't really matter if this is first
	var cmd tea.Cmd
	m.input, cmd = m.input.Update(msg)

	return m, cmd
}

func (m simpleModel) View() tea.View {
	v := tea.NewView("")
	v.AltScreen = true
	if m.ready {
		var content strings.Builder
		if m.pasted != "" {
			content.WriteString("Last pasted string: ")
			content.WriteString(m.pasted)
			content.WriteString("\n")
		}

		content.WriteString(m.input.View())

		v.SetContent(content.String())
	}

	return v
}

Then run it via go run main.go. Once that is done you can open a file in VSCode or any other GUI application that you can copy something from.

Copy something from the file you just opened and then close the GUI you copied it from.

Now go back to the TUI and try to paste. It should cause the program to crash due to an unexpected error of exist status 1.

Source Code
See code above.

Expected behavior
I am not really sure an empty clipboard should result in an error on paste, but that is not really something you have control over as there is an external package used. It would be helpful to expose a specific error type or event a specific error that can then be caught with errors.Is to allow for handling easily outside of the text input bubble.

Screenshots
Add screenshots to help explain your problem.

Additional context
Sample image of what it looks like when the program fails:

Image

So here is what the problem seems to be:

  • Wayland has a security rule where if you close a program, any content copied from it gets removed from your clipboard
  • Wayland uses wl-paste which throws an error whenever the clipboard is empty as can be seen in the next image
Image

I hope this helps. Thanks for all the work that y'all have done!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions