AlecAivazis / survey

A golang library for building interactive and accessible prompts with full support for windows and posix terminals.
MIT License
4.07k stars 349 forks source link

Remove ANSI formatting before measuring string width #462

Closed zimeg closed 1 year ago

zimeg commented 1 year ago

Summary

Hello! This PR hopes to address an issue in the select prompt where formatted lines may delete the past output on terminals of certain sizes.

The problem

When ANSI escape codes are used in the options of a prompt, these lines are measured wider than what is visibly printed to the terminal. This is caused by the StringWidth counting these escaped characters as a part of the actual string, and results in previous output being deleted (if the measured line count is greater than the actual line count of an option).

The following can demonstrate this on terminals that are only slightly wider than the option's visible length:

prompt := &survey.Select{
  Message: "Select an option:",
  Options: []string{
    "\033[35m..........................................................",
    "\033[36m..........................................................",
  },
}

survey.AskOne(prompt, "")

See this in action:

https://user-images.githubusercontent.com/18134219/198906355-71ca8926-61e6-4af0-8c44-9adf03a8604a.mov

Proposed solution

The github.com/acarl005/stripansi library offers a nice regex pattern to remove ANSI codes, and when used in the StringWidth method can remove these codes before the string's width is measured.

Additionally, a check for non-printable runes was added to the runeWidth method so that only printable characters are measured. unicode.IsPrint was chosen over unicode.IsGraphic to conform with the definitions of Go, but I could see a reason for preferring IsGraphic!

With the changes of this PR applied, the following result is achieved:

https://user-images.githubusercontent.com/18134219/198907296-7fcfa73a-4f78-4a20-990a-f203f03202b7.mov

mislav commented 1 year ago

Thank you!

mwbrooks commented 1 year ago

@mislav Some wonderful improvements and bug fixes have landed since September's v2.3.6 release. When you have a moment in the coming months, we'd greatly appreciate a fresh release 🙏🏻 ☺️