-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcd_completion.sh
More file actions
165 lines (146 loc) · 4.6 KB
/
Copy pathcd_completion.sh
File metadata and controls
165 lines (146 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# more natural completion of cd with emnvironment variables
# Usage:
# Source this file, for example in your ~/.bashrc or similar. e.g.
# source cd_completion.sh
##################
# Helper functions
##################
# Return the starting environment variable from the string in $1
extract_env_var() {
if [[ "$1" == *"$"* ]]; then
echo "$1" | grep -o '$[a-zA-Z_][a-zA-Z_0-9]*'
else
echo ""
fi
}
# Returns the contents after an starting environment variable
extract_rest() {
local prefix="$1/"
local path="$2"
if [[ "$path" == "$1"* ]]; then
echo "${path:${#prefix}}"
else
echo "$path"
fi
}
# Returns a list of environment variables starting with the prefix
get_folder_envars() {
local prefix="$1"
readarray -t COMPREPLY < <(compgen -v "$prefix")
# Filter results to only include directories
local results=()
for var in "${COMPREPLY[@]}"; do
if [[ -d "${!var}" ]]; then
results+=("\$$var")
fi
done
COMPREPLY=("${results[@]}")
}
# extracts the relative path of $1 from $2
get_relative_path() {
v1="$1"
v2="$2"
# Remove trailing slash from v2
v2="${v2%/}"
# If v2 is not a prefix of v1, return an empty string
if [[ "$v1" != "$v2"* ]]; then
echo ""
return
fi
# Remove v2 from the beginning of v1 and return the result
echo "${v1#$v2/}"
}
# Returns the corresponding value of a environment variable whose name is in $1
expand_env_var() {
# Get the value of the environment variable and append a slash
prefix="${1%/}"
prefix=${prefix:1}
echo "${!prefix}"
}
# For debug
showXXX() {
echo
echo $1
}
# post processes the COMPREPLY contents so
# 1. it ends with / when an existing folder
# 2. it ends with whitespace when an existing file
# 3. it escapes special characters with printf "%q"
# 4. it deals properly with paths starting with ~
# 5. it deals properly with paths starting with $
postprocess_COMPREPLY() {
local results=()
for var in "${COMPREPLY[@]}"; do
local envar_name=$(extract_env_var "$var")
local to_append=''
if [[ "$envar_name" != "" ]]; then
local expanded=$(expand_env_var "$envar_name")
local rest=$(extract_rest "$envar_name" "$var")
if [[ "$rest" != "" ]]; then
local escaped="$(printf "%q" "$rest")" # escape special chars like whitespace
to_append="$envar_name/$escaped"
else
to_append="$envar_name"
fi
elif [[ "$var" == '~/'* ]]; then
local rest="$(printf "%q" "${var:2}")"
to_append="~/$rest"
else
to_append="$(printf "%q" "$var")"
fi
if eval "[[ -d "${to_append}" ]]"; then
results+=("${to_append%/}/")
elif eval "[[ -f "${to_append}" ]]"; then
results+=("$to_append ")
else
results+=("$to_append")
fi
done
COMPREPLY=("${results[@]}")
# Add nospace option if there is only one completion option
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
compopt -o nospace
fi
}
_completion() {
local completiontype="$1" # 'f' or 'd'
local cur="${COMP_WORDS[COMP_CWORD]}"
local envar_name=$(extract_env_var "$cur")
local cmd="${COMP_WORDS[0]}"
if [[ "$envar_name" == "" && "$cur" != '$' ]]; then # completion without environment variable
if [[ "$completiontype" == "f" ]]; then
readarray -t COMPREPLY < <(compgen -f -- "$cur")
else
readarray -t COMPREPLY < <(compgen -d -- "$cur")
fi
else
if [[ "$envar_name" == "$cur" || "$cur" == '$' ]]; then # not yet completed environment var
# Get environment variables starting with the prefix
local prefix=${cur:1}
get_folder_envars "$prefix"
else # environment var is already completed
local rest=$(extract_rest "$envar_name" "$cur")
local expanded=$(expand_env_var "$envar_name")
local complete="$expanded/$rest"
if [[ "$completiontype" == "f" ]]; then
readarray -t COMPREPLY < <(compgen -f -- "$cur")
else
readarray -t COMPREPLY < <(compgen -d -- "$cur")
fi
fi
fi
postprocess_COMPREPLY
}
######################
# completion functions
######################
_file_completion() {
_completion f
}
_cd_completion() {
_completion d
}
complete -F '_cd_completion' cd
complete -F '_file_completion' cp
complete -F '_file_completion' mv
complete -F '_file_completion' tvim