oh-my-fish / theme-bobthefish

A Powerline-style, Git-aware fish theme optimized for awesome.
MIT License
1.46k stars 225 forks source link

improper handling of paths containing parenthesis #243

Closed epmoyer closed 4 years ago

epmoyer commented 4 years ago

When navigating to a git repo who's path contains a parenthesis, the git prompt incorrectly shows the full path to the right of the git symbol (rather than just the subdirectories below the repo root).

bobthefish_parens_test

Some background: Most of my git repos are in Dropbox, and because I have both a work and a personal Dropbox account, Dropbox (annoyingly, and irrevocably :) ) enforces a root dropbox directory name which contains both a space and parenthesis (specifically, /Users/eric/Dropbox (Personal)/).

For a while I was getting around this problem by using a symbolic link (which contained no spaces or parens), but today I upgraded to the current bobthefish hoping maybe the parens issue had been fixed, and it actually got worse because the current version ignores the symbolic link and uses the "real" path, so now I see the parens problem even when I use my "workaround" and cd to the symbolic link.

Version: OSX 10.14.6 Not sure how to get my bobthefish version, but I ran omf update bobthefish today so presumably it is "current".

epmoyer commented 4 years ago

Solved! I'll make a pull request I guess, but maybe there's a cleaner way to implement the fix (I'm no Fish syntax expert).

The problem is in the function __bobthefish_project_pwd, which uses a regex to replace the project root dir (i.e. $project_root_dir) part of the full path (i.e. $real_pwd) with a blank string (i.e. ''). If $project_root_dir contains parenthesis then they need to be escaped before using the path in a regex.

I changed the line:

set -l project_dir (string replace -r '^'"$project_root_dir"'($|/)' '' $real_pwd)

to:

set -l project_root_dir_escaped (string replace "(" "\("  $project_root_dir)
set -l project_root_dir_escaped (string replace ")" "\)"  $project_root_dir_escaped)
set -l project_dir (string replace -r '^'"$project_root_dir_escaped"'($|/)' '' $real_pwd)

So the whole function now looks like:

function __bobthefish_project_pwd -S -a project_root_dir -a real_pwd -d 'Print the working directory relative to project root'
    set -q theme_project_dir_length
    or set -l theme_project_dir_length 0

    set -l project_root_dir_escaped (string replace "(" "\("  $project_root_dir)
    set -l project_root_dir_escaped (string replace ")" "\)"  $project_root_dir_escaped)
    set -l project_dir (string replace -r '^'"$project_root_dir_escaped"'($|/)' '' $real_pwd)

    if [ $theme_project_dir_length -eq 0 ]
        echo -n $project_dir
        return
    end

    string replace -ar '(\.?[^/]{'"$theme_project_dir_length"'})[^/]*/' '$1/' $project_dir
end

It's possible that a better solution is to just find the length of $project_root_dir and strip that many characters from the left of $real_pwd. Maybe someone who knows the code base (and Fish syntax) better can weigh in with a cleaner or more generalized solution?

epmoyer commented 4 years ago

It turns out that fish has a string escape function which can solve this problem in the more general case.

The following works, and I plan to put it into a PR shortly:

    set -l project_root_dir_escaped (string escape --style=regex $project_root_dir)
    set -l project_dir (string replace -r '^'"$project_root_dir_escaped"'($|/)' '' $real_pwd)