This is a follow-up question to the discussion in:
https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/1394920
Suppose I have a folder ~/tmp
with some files and directories:
$ mkdir a; touch file1.txt; mkdir a/b; mkdir a/c; touch a/d; mkdir a/b/c
I now try to make a completion script to complete filenames in ~/tmp
, but the complete -o filenames
option is only working correctly if the current directory is ~/tmp
.
See the above link for more background information. This is as far as I got:
$ cat setup
_compTest() {
local cur baseFolder
cur="${COMP_WORDS[$COMP_CWORD]}"
baseFolder=~/tmp
compopt -o nospace
COMPREPLY=( $(
cd "$baseFolder"
if [[ ${cur: -1} != "/" && -d $cur ]] ; then
echo "$cur/"
else
compgen -f "$cur"
fi
) )
}
complete -F _compTest aaa
Then I source it:
$ . setup
and I can then do
$ aaa <tab><tab>
Problem 1 : Slashes are not added at the end of directory names in the completion list ( this is desired to easy separate directories from file names in the completion list)
Problem 2 : For aaa a/<tab><tab>
the completion list is a/b a/c a/d
but the a/
prefix should not be there. It should be b/ c/ d
instead.
A relative path refers to a location that is relative to a current directory. Relative paths make use of two special symbols, a dot (.) and a double-dot (..), which translate into the current directory and the parent directory. Double dots are used for moving up in the hierarchy.
An absolute path always contains the root element and the complete directory list required to locate the file. For example, /home/sally/statusReport is an absolute path. All of the information needed to locate the file is contained in the path string.
Paths include the root, the filename, or both. That is, paths can be formed by adding either the root, filename, or both, to a directory.
A relative path is a way to specify the location of a directory relative to another directory. For example, suppose your documents are in C:\Sample\Documents and your index is in C:\Sample\Index. The absolute path for the documents would be C:\Sample\Documents.
We can change the current working directory with change directory function chdir () Relative file path is always going to be relative with current working directory, it won't contain root folder. Let's say there are two folders 'one' and 'two' in my F drive, and 'one' is the cwd.
The directory separator character separates the file path and the filename. The following are some examples of UNC paths: The root directory of the C: drive on system07. The Foo.txt file in the Test directory of the \\Server2\Share volume.
Relative filenames describe files that are referenced relative to an assumed position in the file system. In Figure 3.3, even Personnel/Taylor,D. isn’t unique because that can be found in both Indiana and Washington.
Relative file path is always going to be relative with current working directory, it won't contain root folder. Let's say there are two folders 'one' and 'two' in my F drive, and 'one' is the cwd.
I would write this function as:
_compTest ()
{
local cur; local tmp; local tmp_escaped; local i;
_get_comp_words_by_ref cur;
local _compreply=()
tmp=~/tmp/
tmp_escaped=${tmp//\//\\\/}
cur=$tmp$cur;
if [ "$1" == "-d" ]; then
_cd
else
_filedir;
fi;
for i in "${COMPREPLY[@]}"; do
[ -d "$i" ] && [ "$i" != "$tmp." ] && [ "$i" != "$tmp.." ] && i="$i/"
_compreply=("${_compreply[@]}" "$i")
done
COMPREPLY=(${_compreply[@]/$tmp_escaped/})
} && complete -o nospace -F _compTest aaa_files
_compTestDir()
{
_compTest -d
} && complete -o nospace -F _compTestDir aaa_directories
It has 3 parts,
$cur
with your base directory - ~/tmp._filedir
used for cd/ls etc.~/tmp
from COMPREPLY
Just for the record: You can use this logic to complete the file names relative to many other types of path, e.g.
//...
. http://localhost/*
paths, relative to your public_html
directory.Would have added as a comment, but I don't have the reputation...
Building on @anishsane's answer, if there is only a single completion option and it is not a directory, then you may not want to include the nospace
option. For example, the program may accept another argument after the one you are currently completing. If there is only one option, we should accept that option and move on to the next arg.
To do this, remove nospace
from the complete
line and add logic to enable nospace
only when needed:
# [...]
# Do not include trailing space in results if there is more than one option
# or if the only option is a directory
[ "${#_compreply[@]}" -gt 1 ] && compopt -o nospace
[ "${#_compreply[@]}" -eq 1 ] && [ -d "${_compreply[0]}" ] && compopt -o nospace
COMPREPLY=(${_compreply[@]/$tmp_escaped/})
} && complete -F _compTest aaa_files
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With