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

Prompt changes to ">" when fish thinks it's too long #904

Closed
paulmillr opened this issue Jul 3, 2013 · 48 comments
Closed

Prompt changes to ">" when fish thinks it's too long #904

paulmillr opened this issue Jul 3, 2013 · 48 comments

Comments

@paulmillr
Copy link

Fish 2.0.0. When I cd some directories, my prompt (robbyrussell + small changes) becomes stupid (it has nothing to do with git or with $var in cd, I checked).

screen shot 2013-07-03 at 16 56 04

@ridiculousfish
Copy link
Member

This happens deliberately if the prompt is too wide to fit on the screen. Is that what's going on here?

@KamilaBorowska
Copy link
Contributor

I assume so. The width of shell is 50. The prompt would take 24 characters (if I read it correctly), but it could take way more if read-components is git repository (and this looks like a Node.js package, so it's a possibility). git:master takes 11 characters, so the prompt uses 35 characters (unless of course, it isn't actually master).

Except that doesn't make sense. If the prompt has 35 characters, why it would be too long? I've tried using the prompt he used myself, but I don't see anything wrong.

@rgieseke
Copy link

Is there a way (or example prompts) to handle this in a "responsive" way, e.g. don't display machine info if the prompt is too wide or shorten the directory path to the most significant part?

@KamilaBorowska
Copy link
Contributor

@rgieseke: Sure, check $COLUMNS variable. It's somewhat difficult to do it, but it's possible (you may want to check length of variables with echo -n $var | wc -c for responsive prompts).

@JoshCheek
Copy link

This has been an issue for me, too. Personally, I'd rather it wrap my prompt or truncate it or give me the option to override this default prompt. The ">" is really rough for me, I have an emotional dependency on a coloured prompt, and possibly also on seeing the cwd. Without that, I feel lost.

@wwwjfy
Copy link
Contributor

wwwjfy commented Jul 22, 2013

That bothers me, too. I've asked in mail list, no sequential follow-ups though.

I looked up the commit history and found the comment in screen.cpp

    /*
      Ignore prompts wider than the screen - only print a two
      character placeholder...

      It would be cool to truncate the prompt, but because it can
      contain escape sequences, this is harder than you'd think.
    */

I propose that if an env var set (like FISH_WRAP_LONG_LINE), then we skip those lines in screen.cpp to make the prompt "> ".

Something like this.

    env_var_t wrap = env_get_string(L"FISH_WRAP_LONG_LINE");
    if (wrap.missing())
    {
        if (left_prompt_layout.max_line_width >= screen_width)
        {
            /* If we have a multi-line prompt, see if the longest line fits; if not neuter the whole left prompt */
            left_prompt = L"> ";
            left_prompt_width = 2;
        }
    }

    if (left_prompt_width + right_prompt_width >= screen_width)
    {
        /* Nix right_prompt */
        right_prompt = L"";
        right_prompt_width = 0;
    }

    if (wrap.missing())
    {
        if (left_prompt_width + right_prompt_width >= screen_width)
        {
            /* Still doesn't fit, neuter left_prompt */
            left_prompt = L"> ";
            left_prompt_width = 2;
        }
    }

@KamilaBorowska
Copy link
Contributor

$FISH_WRAP_LONG_LINE won't pass. fish tries to avoid configuration by design, and this reminds me options like "**/ support" in zsh.

@wwwjfy
Copy link
Contributor

wwwjfy commented Jul 22, 2013

@glitchmr I read the design document, but I don't know what the alternative way is.

Actually, by greping the source code, there are some configurations, including FISHD_SOCKET_DIR, TERM, fish_term256, fish_function_path, FISH_CLIPBOARD_CMD, etc... it's not the whole, but here is the idea.

As the comment I pasted there said, the difficulty is about the escape sequence. I've no experience about that, but I assume long-line wrap is more regular than that. (Or it's quite common just I don't know what it is? Could anyone give an example of that which will cause the problem� wrapping)

I myself don't like to use another variable, either. I'll be more than happy to have a better solution to satisfy both.

@zanchey
Copy link
Member

zanchey commented Jul 26, 2013

On the mailing list, Peter suggests defining a new fish_short_prompt function.

Wrapping the prompt is a possibility; truncating it is where we run into problems with control characters. (e.g. consider truncating a prompt which sets the proxy icon in OS X ala #68).

We would all like to avoid magic variables and new functions (fish_short_prompt, fish_really_short_prompt).

I also think that wrapping lacks elegance, and has the potential to produce pathological scenarios. Consider the case where a user accidentally includes git log instead of git log -n... wrapping would quickly destroy the terminal and possibly make it very difficult to correct the problem. However, at least the cause would be quickly evident, whereas the truncation to > is clearly causing a bit of surprise.

It would be great if we had an example of how to inspect $COLUMNS and alter the prompt accordingly.

@wwwjfy
Copy link
Contributor

wwwjfy commented Jul 27, 2013

@zanchey I don't get it that why git log will make wrapping not work. I tried to include git log in fish_prompt, and made the terminal narrow, and the output was just ugly, but I can see what's that.

By wrapping I mean fish does nothing, leaving it to the terminal, and as my trial to remove the two ifs in my previous post, the terminal can wrap it. No doubt it's not elegant, but a workable version first, then we consider about elegance, right? > was a big surprise, and I've no idea what $PWD is.

I'd like to know a case the wrapping doesn't work. (I'm using iTerm2 under Mac OS X, no idea if iTerm2 has anything special)

Regarding the $COLUMNS, I think we can borrow something from responsive website design to fit different widths.
The rough idea is like

set part1 "what I think cannot be divided"
set part2 "here is part2"
echo -n $part1
if [ (expr length $part1$part2) -gt $COLUMNS ];
    echo
end
echo $part2

Skip the escape sequences.

Even though there will be a function to automatically do the job (The function will be easy to implement), it's still way too complicated for a simple concept.

@ridiculousfish
Copy link
Member

Most of the problems associated with wrapping revolve around cursor motion, window resizing, and fish_right_prompt. Wrapping the prompt is probably doable, it's just tricky.

@franciscolourenco
Copy link

Truncating would still be more desirable than the arrow in the meanwhile.

@zanchey
Copy link
Member

zanchey commented Jul 17, 2015

Truncating is actually harder because of control sequences.

@damienmckenna
Copy link

Was about to open an issue for this, glad I kept searching.

@faho faho changed the title Sometimes prompt becomes a simple arrow Prompt changes to ">" when fish thinks it's too long Apr 25, 2016
@flibby-jibbit
Copy link

Coming to the party late. Sorry.

I ran into this issue the other day, and stupidly tried to figure out what was going on before I searched for it. After wasting a few hours, it finally dawned on me what was going on. Then I searched (facepalm). Anyway, I just updated my fish_prompt function to adjust the directory if the prompt is too long. So far, it looks promising.

Like a lot of people, I put the branch name in the prompt if I'm in a Git repository. Unlike a lot of people, though, I use a two line prompt where prompt line 1 is all the information and prompt line 2 is the "command entry point", so to speak. In my situation, I have to put together the content of pl1 to see if it's too long, and then adjust the directory if necessary. It's kind of cumbersome, but it does work.

  # other stuff happens first, like setting some color variables and things that are irrelevant
  # to this discussion.

  ...

  # get the current dir nicely ... replace $HOME with "~"
  set -l realhome ~
  set -l dir (string replace -r '^'"$realhome"'($|/)' '~$1' $PWD)

  # start with the "full" directory
  set -l pl1 "[$USER] $dir"

  # try to get the current branch
  set -l git_branch (git rev-parse --abbrev-ref HEAD 2> /dev/null)

  if test "$git_branch" != ""
    # we have a branch, so let's add that in
    set pl1 "$pl1 ($git_branch)"
  end

  # get the length
  set -l pl1_len (string length $pl1)

  if test $pl1_len -gt $COLUMNS
    # too long, use the shortened version of dir instead
    set dir (prompt_pwd)
  end

  # we can now build common pieces of the prompt, but because we need to 
  # choose colors based on state, we have to reevaluate some things
  set -l prompt_line_1 '\n%s[%s] %s%s%s'
  set -l prompt_line_1_args "$user_color" $USER "$color_blue" "$dir" "$color_normal"
  set -l prompt_line_2 '%s->%s '
  set -l prompt_line_2_args "$shell_status_color" "$color_normal"

  if test "$git_branch" != ""
    # start by assuming the working dir is dirty
    set -l git_status_color $color_red

    git status | grep clean > /dev/null
    if test $status -eq 0
      # Oh, no changes, so let's use green for the git branch
      set git_status_color $color_green
    end

    set -l git_prompt '%s(%s)%s'
    set -l git_prompt_args "$git_status_color" "$git_branch" "$color_normal"
    set prompt_line_1 "$prompt_line_1 $git_prompt"
    set prompt_line_1_args $prompt_line_1_args $git_prompt_args
  end

  # All together now ...
  set -l prompt_string "$prompt_line_1\n$prompt_line_2"
  set -l prompt_args $prompt_line_1_args $prompt_line_2_args

  printf $prompt_string $prompt_args

I use tmux all day and have been using pane zooming (Prefix z). When zooming in and out, the prompt changes accordingly.

I hope someone finds this useful or could recommend ways to make it better.

@ghost
Copy link

ghost commented Apr 1, 2017

I use a two line prompt as well. I believe, many people do.

To get arround this issue I put the first line with all the interesting stuff in a function --on-event fish_prompt. This way fish shell will let this line alone no matter what. The second line is the actual prompt. It's just '$ ', and hence just as good as '> '.

Edit:
As a neat side effect, things like virtualenv that prefix your prompt, will prefix the second line.

@JoshCheek
Copy link

That's what I do, too. Too hard to track where to look when the location changes across lines.

screenshot 2017-03-31 21 22 52

@christianrondeau
Copy link
Contributor

Adding some (hopefully useful) feedback to this.

I also had "sometimes" the > prompt appearing, and I thought that there was some silent crash in my script for some time. I recently started digging (read: uncomment lines one by one) until I realized prompt_pwd was the one causing this. It's only after trying to dig into the prompt_pwd code that I realized it had nothing to do with this. This was a few hours trying to figure out something that could have been avoided by implementing this differently.

I understand the no-configuration philosophy, but I think here discoverability is one problem, and the other is "ignoring" my prompt by replacing it by another (rule of least surprise).

So here's my idea:

  • If you offer customizing fish_prompt, I think you should at least have a fish_short_prompt_character if you're going to fallback to this, and you don't believe in using fish_short_prompt (which I do understand).
  • If you are going to fallback to the > prompt, an ugly but friendly solution would be to tell me about it. As an example, print fish: could not print prompt, because it is too long.. This way, if I use the default prompt I wouldn't see this, but if I made mine, I'll immediately know what the problem is and what to search for.

Let me know what you think!

@mvolkmann
Copy link

@aramiscd, can you post some example code showing how you solved this?

@krader1961
Copy link
Contributor

I'm inclined to agree with @christianrondeau that fish should definitely issue an explanatory message about why the output of fish_prompt is being ignored. On the other hand I don't see the point of something like fish_short_prompt_character. In keeping with historical practice there's really only a couple of reasonable choices: > and $. Allowing the user to select the specific character seems rather pointless. But I do think we should support a fish_short_prompt function as a fallback. If its output is still too long for the current terminal width then fallback to > with a warning message.

@floam
Copy link
Member

floam commented Aug 13, 2017

In keeping with historical practice there's really only a couple of reasonable choices: > and $
I believe we have prompts we ship with fish which use some interesting unicode character for the prompt.

@krader1961
Copy link
Contributor

By "historical practice" I'm talking about shells like the original Bourne shell. And if we're so desperate to display any sort of prompt that we're falling back to displaying a single character prompt it's hard to justify introducing colors and non-ASCII characters.

@christianrondeau
Copy link
Contributor

@krader1961 my thinking was that a "one-character fall back prompt" is a "short prompt" (albeit a very short one). Right now I have to do some crazy string concatenation to check if the prompt does not fit: https://github.com/christianrondeau/dotfiles/blob/master/fish/.config/fish/functions/fish_prompt.fish#L42 - I'd like my prompt on my phone to still be "my" prompt, rather than > if I could.

I think having any way to fall back to anything (be it a short_prompt, single-character prompt config, or even better a built-in way to pass prompt components that support a long and short version, though that's out of the scope of that discussion I think) is the "useful" thing. The "important" thing is to at least know where that came from :)

Since that seems to be an opinionated topic, and I now have a fallback, I'd suggest to "solve" this specific issue with a simple useful message, and all short prompt ideas could become issues on their own. I do believe however that if we include the useful message in the short prompt itself (e.g. Prompt too long\n>), it will be possible for people who don't care about this to easily turn it off.

@floam
Copy link
Member

floam commented Aug 14, 2017

I like the idea of only using the fallback when the actual prompt does not fit. One could check $COLUMNS in fish_prompt and try to provide what they want based on the space available. Fish then would force the fallback only if the prompt author failed to provide their own one that size.

@ridiculousfish ridiculousfish modified the milestones: fish-3.0, fish-future Apr 15, 2018
@JoshCheek
Copy link

What about using the prompt's last nonwhitespace character for the single-character prompt? The likelihood is very high that it is what the user would choose.

@AntonioND
Copy link

Truncating may be a problem, there may be escape sequences that start a format but the sequence that ends it may be truncated (so the format may continue in the following line). If you just wrap around, even if it doesn't look great, at least the prompt doesn't behave in a different way than when it is not truncated.

@AntonioND
Copy link

AntonioND commented Apr 15, 2018

@JoshCheek but why one character? I honestly don't know why removing all the information from the prompt is a good idea. I have a long prompt because I want that information. If I didn't care at all about it I would simply have a shorter prompt.

And again, if that's what you want, you can edit the function to do it.

@peey
Copy link

peey commented Jun 9, 2018

Here's what I've done to dynamically make my prompt smaller based on $COLUMNS. Might be useful with modifications to someone else. If the adapted version is too long then fish will fall back to > anyways, but this is good enough for me.

It wasn't exactly straightforward, so I don't think customizing is that easy and there should be better support in fish for handling this

I'm using a theme (cbjohnson) which uses a 2-line prompt, modify to suit your needs

functions --copy fish_prompt fish_original_prompt

function fish_medium_prompt
  # remove user@machine from prompt. For the theme cbjohnson it is the first four words of the first prompt line
  set first_line (fish_original_prompt | head -n 1)
  set rest (fish_original_prompt | sed -e '1d')

  echo "$first_line" | cut -d ' ' -f5-
  echo "$rest"
end

function fish_constrained_prompt 
  # force wrap prompt to $COLUMNS - 5 length
  set acceptable (echo $COLUMNS "- 5" | bc)
  fish_medium_prompt | fmt -w $acceptable 
end

function fish_prompt
  # color removal for correct length calculation from https://stackoverflow.com/a/18000433/1412255
  set original_length (fish_original_prompt | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | wc -L)
  set acceptable (echo $COLUMNS "- 5" | bc)

  set cmp (echo $original_length "<" $acceptable | bc)
  if [ $cmp = 1 ] 
    fish_original_prompt
  else 

    set modified_length (fish_medium_prompt | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | wc -L)

    set cmp (echo $modified_length "<" $acceptable | bc)
    if [ $cmp = 1 ] 
      fish_medium_prompt 
    else
      fish_constrained_prompt
    end
  end
end

I wasn't able to put the color-removing / prompt length calculation logic in a separate function. I think it's likely some issues with fish (I was stuck because of this, and even if I don't pipe stdin and rely on $argv, I'm still unable to get it to work).

Also fmt doesn't break a word if it's too long :/ so it won't work if your directory name / path is long, but the alternatives are worse (fold doesn't count unicode characters properly - so breaks git status, and par has problems with colored input I think)

In case anyone finds a way to improve the above, please do share.

@gkatsanos
Copy link

I opened this one oh-my-fish/oh-my-fish#627 - I'm trying to do something similar I guess (control how it looks), first letter really isn't useful, I'd prefer only last directory

@faho
Copy link
Member

faho commented Jul 17, 2018

@gkatsanos: Since fish 2.3.0, the prompt_pwd function that prompts typically use to get the pwd honors the $fish_prompt_pwd_dir_length variable. Set that to the number of characters per-directory or 0 for no shortening.

@znculee
Copy link

znculee commented Jul 17, 2018

znculee/fish-theme-xtli
I forked a theme from oh-my-fish/theme-cbjohnson and revised it to be able to abbreviate prompt_pwd when the terminal become narrow, shown as following figure.
image
The key idea is to detect the number of columns of the top line of the prompt, and compare it with $COLUMNS to perform different prompt when the terminal become narrow of the prompt become too long.

@mixmastamyk
Copy link

Any news here? I've lost my prompt and wondering what to do.

Also > is a character to avoid in prompts because it it is dangerous on cut and paste. I use a unicode replacement.

I usually have the pwd shortening off, but would prefer it to this kind of shortening. How could I do that? Divide $COLUMNS by two and change the setting?

@znculee
Copy link

znculee commented Oct 12, 2018

@mixmastamyk You may want to try this theme znculee/fish-theme-xtli.

edouard-lopez pushed a commit to pure-fish/pure that referenced this issue Dec 11, 2018
Reimplement workaround for truncated strings (#49) using single function as currently recommended in fish-shell/fish-shell#904 (comment) instead of event handler.

Update first line of the prompt when moving through directory history with "Alt + ←" and "Alt + →" (#66).

Also resolve #62 and #67.

Refactor code into smaller functions.
@lionello
Copy link

lionello commented Feb 20, 2019

Inspired by @wwwjfy, I ended up adding the following code to my ~/.config/fish/functions/fish_prompt.fish, right before the echo that prints the prompt:

    # shorten the prompt, but only when it's too long
    set -g fish_prompt_pwd_dir_length 0
    set -l longprompt $USER (prompt_hostname) (prompt_pwd) (__fish_vcs_prompt) $prompt_status
    if test (expr length "$longprompt") -gt $COLUMNS
        set -g fish_prompt_pwd_dir_length 1
    end

@DustVoice
Copy link

DustVoice commented Oct 24, 2019

Inspired by @wwwjfy, I ended up adding the following code to my ~/.config/fish/functions/fish_prompt.fish, right before the echo that prints the prompt:

    # shorten the prompt, but only when it's too long
    set -g fish_prompt_pwd_dir_length 0
    set -l longprompt $USER (prompt_hostname) (prompt_pwd) (__fish_vcs_prompt) $prompt_status
    if test (expr length "$longprompt") -gt $COLUMNS
        set -g fish_prompt_pwd_dir_length 1
    end

Unfortunately this didn't satisfy my requirements. That's why I have written a script that does line wrapping of the prompt, as well as trimming of too long directory names for me.

If you're just here for the solution scroll to the bottom of this post.

Why this is a problem

Imagine for example if you have a directory

user@machine ~/very_long_directory_name_so_that_with_a_lower_columns_number_you_will_experience_the_described_behaviour/aab/dir
$

and a directory

user@machine ~/very_long_directory_name_so_that_with_a_lower_columns_number_you_will_experience_the_described_behaviour/aax/dir
$ 

fish would abbreviate both directories to

user@machine ~/v/a/dir
$ 

when using set fish_prompt_pwd_dir_length 1, where one would hope that it would abbreviate it after the first identifiying character instead. This leads to a huge amount of confusion, as the directory dir/ is present in both the directory aab and aax.

Imagine for example you have the following directories:

user@machine ~
$ ls
aaab/ aaba/ az/

fish doesn't abbreviate aaab to aaa, aaba to aab and az to az, or something like this, but instead abbreviates all of them to a sole a.

This is just really unfortunate, because why should I bother to have a directory display in my prompt in the first place, if I have to manually issue pwd evertime?!

How to solve this problem

Thats why I developed a script that automatically wraps directory strings that are too long (splitting the path at the / symbol) and trims the directory names that are too long.

In my case

user@machine ~/very_long_directory_name_so_that_with_a_lower_columns_number_you_will_experience_the_described_behaviour/aax/dir
$ 

would become (with $COLUMNS equal to 50 for example)

user@machine ~/
> very_long_directory_name_so_that_with_a_lower_colu[...]/
> aax/dir
$

Of course this solution isn't perfect, but it's sufficient for me at least.

The solution

To view the script, please consult my construct_column_aware_prompt.fish function for the function itself, as well as my fish_prompt.fish config on how to use said function.

@thefossguy

This comment has been minimized.

@ridiculousfish
Copy link
Member

I took a run at truncation. The approach is that, for each line of the prompt whose width exceeds $COLUMNS, we prepend ellipsis and then start removing characters from the left until it fits, while skipping escape sequences. I chose the left because it probably has the least interesting information (e.g. parent directories).

I personally prefer very minimalist prompts so probably this will need to be refined by someone who uses it. I think it's best to open new issues for any changes, as this one has been quite worked over.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests