nushell / reedline

A feature-rich line editor - powering Nushell
https://docs.rs/reedline/
MIT License
499 stars 134 forks source link

`reedline::prompt::base::Prompt` should be redesigned #526

Open cactusdualcore opened 1 year ago

cactusdualcore commented 1 year ago

As I already noted here, the current implementation for prompts does not behave well under certain conditions (e. g. if reedline::prompt::base::Prompt returns a string containing control characters i. e. line breaks and carriage returns or if ) and it is missing at least a specification for how certain features should work together (e.g. multiline input and completions)

image _Fig 1. Prompt::render_prompt_right returns a string with line break_

image Fig 2. the same as Fig 1. but in a different terminal

image Fig 3. prompts can be longer than terminal width

image Fig 4. it works with whitespace

(For none of the above have I resized the terminal window)

cactusdualcore commented 1 year ago

My suggestion would be to design the prompt as something like this

[          header          ]
[ before ] <input> [ after ]
[          footer          ]

or, for multiline input

[          header          ]
[ before ] <input>
[continuation] <input>
...
[          footer          ]

where header and footer are optional multiline strings i. e. Option<&str> that never spill into the area of user input because they are rendered before and after respectively. after is a single-line string rendered after the user input if it does not span multiple lines. before is a single-line string on the first line and on all following lines for multi-line input it's continuation.

This should make painting to screen pretty straightforward I hope, because this now only requires the on screen position of the current prompts position. Then follow these steps to paint

  1. render header to terminal
  2. insert line break if header didn't end with one
  3. render before or continuation to terminal
  4. render next line of input to terminal
  5. repeat steps 3 and 4 until all lines have been rendered
  6. If it was only one line, render after
  7. insert line break if header didn't end with one
  8. render footer

This is indifferent whether you want to repaint an existing prompt or paint a new one. For the latter use the first line after the last command's response as the new response. This also accounts for #348, because using one of two different prompts for painting easily achieves this functionality.

cactusdualcore commented 1 year ago

As this now uses before and after this can easily be mirrored in the rendering step for right-to-left prompts.

cactusdualcore commented 1 year ago

I should add this is in fact similar to what is done currently. I am asking for well defined and structured behavior.

robrecord commented 10 months ago

starship prompt and oh-my-posh prompt are not able to use a transient prompt without this or something similar.