Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

External process input errors when using cmd.exe #923

Open
grafviktor opened this issue Feb 11, 2024 · 3 comments
Open

External process input errors when using cmd.exe #923

grafviktor opened this issue Feb 11, 2024 · 3 comments

Comments

@grafviktor
Copy link
Contributor

Describe the bug
When use bubbletea app to run an external process on Windows OS, the process looses first character of the user input.

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

  • Windows 10
  • cmd.exe
  • Tested on github.com/charmbracelet/bubbletea v0.24.2 and v0.25.0

To Reproduce
Steps to reproduce the behavior:

  1. Create a project using the source code below. Place echo_input.cmd in the project's folder.
  2. Open cmd.exe, go to the project folder, and run the app: go run main.go
  3. Once the app started press up or down arrow keys
  4. Press e to run external process (the process will launch echo_input.cmd)
  5. Press 1 2 3 sequence on your keyboard
  6. Notice that only 23 was printed on your screen. Press enter key.
  7. Press any key to exit from the external process
  8. Notice that your lost character 1 was intercepted by the model's update method

Source Code

// main.go
package main

import (
	"fmt"
	"os"
	"os/exec"

	tea "github.com/charmbracelet/bubbletea"
)

type editorFinishedMsg struct{ err error }

func runExternalProcess() tea.Cmd {
	c := exec.Command("cmd", "/c", "echo_input.cmd")
	return tea.ExecProcess(c, func(err error) tea.Msg {
		return editorFinishedMsg{err}
	})
}

type model struct {
	input string
	err   error
}

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.KeyMsg:
		switch msg.String() {
		case "e":
			return m, runExternalProcess()
		case "ctrl+c", "q":
			return m, tea.Quit
		default:
			{
				if msg.Type != tea.KeyUp && msg.Type != tea.KeyDown {
					m.input = string(msg.Runes)
				}
			}
		}
	case editorFinishedMsg:
		if msg.err != nil {
			m.err = msg.err
			return m, tea.Quit
		}
	}
	return m, nil
}

func (m model) View() string {
	if m.err != nil {
		return "Error: " + m.err.Error() + "\n"
	}
	return fmt.Sprintf("Press 'e' to test input.\nPress 'q' to quit.\nLost character: %s", m.input)
}

func main() {
	if _, err := tea.NewProgram(model{}, tea.WithAltScreen()).Run(); err != nil {
		fmt.Println("Error running program:", err)
		os.Exit(1)
	}
}
rem echo_input.cmd
@echo off
set /p user_input=Enter 123:
echo You entered: %user_input%
pause

Expected behavior
All user input should be redirected to external process

@grafviktor
Copy link
Contributor Author

grafviktor commented Feb 13, 2024

It's readInputs function who steals the first char from the external process.

@meowgorithm
Copy link
Member

Okay cool: so we have an PR open (#878) that overhauls input on Windows which will likely fix this. Would you mind checking on your end @grafviktor?

@grafviktor
Copy link
Contributor Author

grafviktor commented Feb 14, 2024

Okay cool: so we have an PR open (#878) that overhauls input on Windows which will likely fix this. Would you mind checking on your end @grafviktor?

Unfortunately, the patch makes things even worse - with every N process which I run from my example app, readInputs steals N+1 symbols. Also it forwards the ending Enter('\r') key which I send to the running process back to the model.

I put a comment beneath Ayman's PR to keep him in the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants