ogham / rust-ansi-term

Rust library for ANSI terminal colours and styles (bold, underline)

Home Page:https://crates.io/crates/ansi_term

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Text wrap broken when using ansi_term in shell prompts

glfmn opened this issue · comments

commented

Background

I made a crate called glit, or Glitter which is a domain specific language for pretty printing git repository stats. The primary use-case is to embed information about git repository stats in a user's shell prompt; for example:

glit-demo

ansi_term has been super helpful in supporting ansi terminal formatting as part of the Glitter DSL, but I've unfortunately come across a strange issue:

When I have formatted text in the shell prompt, the text wrapping is broken. More specifically:

  • The terminal emulator wraps before the end of the line
  • The terminal emulator wraps onto the same line, overwriting the shell prompt

This issue is related to the way that BASH prompts expect all non-printing characters to be properly escaped so that it can properly count the length of a line.

Examples

Gnome shell
in gnome shell terminal emulator

hyper
demonstration in hyper.is terminal emulator

Expected Behaviour

The terminal again behaves as expected when I don't use any formatted text on the last line of the prompt; notice how below there is no formatting on the line which just contains $ ; that line was created by the interpreter by rendering the text \$ with Style::new(), or no formatting set.

  • The line wraps at the end of the line
  • The text does not wrap onto the same line as the shell prompt

demonstration of expected ansi_term behaviour

This has to do with lack of escapes for non-printing characters in bash prompts; from the documentation, control sequences must be escaped with:

\[

    Begin a sequence of non-printing characters. This could be used to embed a terminal control sequence into the prompt. 
\]

    End a sequence of non-printing characters. 

Replication

  • OS: Ubuntu 17.10 amd-64bit
  • uname -r: 4.13.0-32-generic
  • cargo -V: cargo 0.24.0 (45043115c 2017-12-05)
  • rustup -V: rustup 1.7.0 (813f7b7a8 2017-10-30)
  • rustc -V: rustc 1.23.0 (766bd11c8 2018-01-01)
  • ansi_term: 0.9^
  • bash --version: 4.4.12(1)-release

Those aren't ANSI escapes, they're specific to bash's prompt. ansi_term can't emit those under normal circumstances, and I don't think it makes sense to have an option to do so that's specific to the bash prompt use case.

Ideally, bash should really be able to figure this out itself, such as by getting the current position after displaying the prompt. In the meantime, it's currently guaranteed that every sequence emitted by ansi_term will start with the byte \x1B, contain one or more characters other than m, and end with the byte m, so you could fairly easily insert the \[ and \] bash sequences with a regex or string manipulation inside your program. If you end up writing that code, you might consider providing it as a bash_prompt_ansi crate or similar.