originally inspired by https://gist.github.com/irsdl/5fc80ebad0d6fa211d3efdec288250a6
#examples:
#cdw C:\Use[tab]
#cdw C:\Program\ [double tab]
#cdw "C:\Program Files\[double tab]
#
#lsw should also work, eg lsw -lh C:\Use[tab]
#
#experimental support for cd to accept windows path as well
#eg it can handle both cd /home and cd C:\
#i havent tested it very much
#
#should be easy to add support for other commands
#make use of CDPATH somehow, eg simple CDPATH=/mnt/c/Users/$USER we can then just do cd Desktop without all the below
#we can also add some additional paths that currently are not handled by wslpath, eg ~
COMP_WORDBREAKS=${COMP_WORDBREAKS//:} #removes : from word breaks
#converts from /mnt/xxx to C:\xxx, custom implementation since wslpath always returns the target path if we are dealing with a symlink
function wslpath_to_win() {
local path_parts win_path
IFS=/ read -r -a path_parts <<< "$1"
win_path=$(IFS=\\; echo "${path_parts[2]}:\\${path_parts[*]:3}" )
echo "${win_path}"
}
function wslify_args_and_run() {
local arg f fmeta process_only_paths=false new_args=()
f="$1";shift
fmeta=("$f")
[[ $f = builtin\ * ]] && fmeta=(builtin "${f#builtin }")
for arg in "$@"; do
[[ $process_only_paths == true || $arg != -* ]] && arg="$(wslpath "${arg}")"
[[ $arg == -- ]] && process_only_paths=true
new_args+=("$arg")
done
"${fmeta[@]}" "${new_args[@]}"
}
function cdw() {
wslify_args_and_run "builtin cd" "$@"
}
function lsw() {
wslify_args_and_run ls "$@"
}
function _wslcomp_ls() {
local custom_compgen_args=("-f")
_wslcomp "$@"
}
function _wslcomp() {
local cur mod_cur trcur current_comp wpath path_parts debug=0
local compgen_args=("-d")
[[ -n $custom_compgen_args ]] && compgen_args=("${custom_compgen_args[@]}")
function p() {
local of=/dev/fd/1
[[ $debug -eq 0 ]] && of=/dev/null
echo "$@" >$of
}
cur=$(_get_cword)
if [[ $cur != ?:* && $cur != ??:* ]]; then #test if we are looking to windows paths acceptable by wslpath, eg only c:\xxx, not very important limits possibility for issues with _wcd
p "not supported windows path in arg: $cur"
return 0
fi
#manually fix some escaped characters, not sure if this the right way, likely there is an alternative to _get_cword that does this job?
#maybe look into how _cd does this (run `type _cd`)
#in any case, we remove leading/trailing double quotes and replace "\ " with " "
mod_cur="$cur"
mod_cur="${mod_cur#\"}"
mod_cur="${mod_cur%\"}"
mod_cur="${mod_cur//\\ / }"
#[[ $mod_cur = \~* ]] && {
# mod_cur="${mod_cur#?}"
# mod_cur="C:\\Users\\${USER}${mod_cur}"
# p "Expanded tilde to: $mod_cur"
# we need a good way to replace cu
#}
trcur=$(wslpath "$mod_cur") #converts from C:\xxx to /mnt/xxx
p "cur=$cur mod_cur=$mod_cur trcur=$trcur"
while IFS= read -r -d '' current_comp; do
#wpath=$(wslpath -w "$current_comp") #we avoid this since symlinks get expanded which causes issues
wpath=$(wslpath_to_win "$current_comp")
p "@@@@@ current_comp=${current_comp} @@@@@@@@@ wpath=${wpath} @@@@@@@@@@"
COMPREPLY+=("\"${wpath}\"")
done < <(compgen "${compgen_args[@]}" -- "$trcur"|tr '\n' '\0')
}
complete -o nospace -F _wslcomp cdw
complete -o nospace -F _wslcomp_ls lsw
alias lsw='lsw --color=auto'
#remove everything hereafter and just use cdw if overwriting cd causes issues, one sideeffect is the suppression of stderr for the current cmd
function _wcd() {
_wslcomp "$@"
[[ ${#COMPREPLY[@]} -eq 0 ]] && "${_prev_cd_comp}" "$@"
}
#untested
function is_win_path() {
return $(wslpath "$1" >/dev/null)
}
#kind of clumsy implementation, it makes the assumption that if the built cd fails then we are likely dealing with a windows path
#and that the failed builtin cd command doesnt have any sideeffects. maybe another implementation is to first iterate the cd args
#to see if we can find a windows dir, eg using something like the is_win_path
function cd() {
2>/dev/null builtin cd "$@" || cdw "$@"
}
_prev_cd_comp=$(complete -p cd|grep -oe '-F [^ ]*'|awk '{print $2}')
complete -o nospace -F _wcd cd