mabvmex
mabvmex

Reputation: 53

fish function prompt_pwd but in zsh?

I am currently using ZSH, but I have seen that the Fish Shell has a feature called prompt_pwd which is a function. It displays the prompt path similar as this:

// normally this would apper like this:
$ /my/computer/User/Local/Documents/Something

// prompt_pwd function on fish shell:
$ /m/c/U/L/Documents cd Something
$ /m/c/U/L/D/Something

According you navigates through your file system the full name of them changes to only the first letter of its name and the only full name will be displayed on the current directory...

Do you know how I can achieve this in ZSH?

Thanks!

This is the full code extracted from the fish_config wizard:

    # Defined in /opt/homebrew/Cellar/fish/3.5.1/share/fish/functions/prompt_pwd.fish @ line 1 function prompt_pwd --description 'short CWD for the prompt'
    set -l options h/help d/dir-length= D/full-length-dirs=
    argparse -n prompt_pwd $options -- $argv
    or return

  if set -q _flag_help
        __fish_print_help prompt_pwd
        return 0
    end

  set -q argv[1]
    or set argv $PWD

  set -ql _flag_d
    and set -l fish_prompt_pwd_dir_length $_flag_d

  set -q fish_prompt_pwd_dir_length
    or set -l fish_prompt_pwd_dir_length 1

  set -l fulldirs 0
    set -ql _flag_D
    and set fish_prompt_pwd_full_dirs $_flag_D

  set -q fish_prompt_pwd_full_dirs
    or set -l fish_prompt_pwd_full_dirs 1

  for path in $argv
        # Replace $HOME with "~"
    set -l realhome ~
        set -l tmp (string replace -r '^'"$realhome"'($|/)' '~$1' $path)

    if test "$fish_prompt_pwd_dir_length" -eq 0
            echo $tmp
        else
            # Shorten to at most $fish_prompt_pwd_dir_length characters per directory
      # with full-length-dirs components left at full length.
      set -l full
            if test $fish_prompt_pwd_full_dirs -gt 0
                set -l all (string split -m (math $fish_prompt_pwd_full_dirs - 1) -r / $tmp)
                set tmp $all[1]
                set full $all[2..]
            else if test $fish_prompt_pwd_full_dirs -eq 0
                # 0 means not even the last component is kept
        string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*' '$1' $tmp
                continue
            end

      string join / (string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*/' '$1/' $tmp) $full
        end
    end end

Upvotes: 2

Views: 677

Answers (3)

Kira
Kira

Reputation: 1

setopt extended_glob
print ${(j:/:)${(s: :):-${${(s:/:)${(A)pwd::=${PWD/#$HOME/\~}}}[1,-2]//(#m)^.?*/${MATCH[1]}} ${${pwd:t}:-/}}}

Upvotes: 0

rowboat
rowboat

Reputation: 428

prompt_pwd ()
  psvar[1]="${(@j[/]M)${(@s[/]M)PWD##*/}#?}$PWD:t"

precmd_functions+=( prompt_pwd )
PS1='%1v%# '

This approach does not perform tilde replacement like the %~ prompt sequence does. It shortens the $PWD variable by splitting it into its components, keeping only the first character of each component by using #? with the (M) flag, then joins them together. This process is only applied to the part before the last / separator. The "tail" component is appended to the end.

With ~ replacement for the home directory, and extending #? to ##(.|)? so that the first character after the dot is shown for dot-directories:

prompt_pwd () {
  local p=${${PWD:/~/\~}/#~\//\~/}
  psvar[1]="${(@j[/]M)${(@s[/]M)p##*/}##(.|)?}$p:t"
}

Upvotes: 2

Gairfowl
Gairfowl

Reputation: 2981

This should match your initial text example; add it to ~/.zshrc:

setopt prompt_subst
PROMPT='\$ /$(printf "%.1s/" ${(s./.)PWD:h})${PWD:t} '
  • (s./.) - splits a path at /.
  • printf "%.1s/" - prints the first character of each directory piece.
  • ${PWD:h} - the 'head' of the current directory, i.e. everything but the last element.
  • ${PWD:t} - the tail / last element in the directory path.

Adding colors and other characters is a bit more involved. When building a complicated prompt, it's often easier to use a precmd; some of the many posts that discuss prompt colors and precmds are here, here, and here.


Edited to add:
As @rowboat noted, the code above will include an extra / in top-level directories like /tmp. This is due to printf always including at least one result even when there are zero parent directories. One fix is a substitution to convert double // to /:

PROMPT='\$ ${${:-$(printf "/%.1s" ${(s./.)PWD:h})/${PWD:t}}/\/\///} '

Similarly, another substitution can be added to escape % as %%, if you need to handle directory names that start with a percent sign:

PROMPT='\$ ${${${:-$(printf "/%.1s" ${(s./.)PWD:h})/${PWD:t}}/\/\///}//\%/%%} '

Upvotes: 1

Related Questions