Perform tilde expansion when completing flake fragments

Allows completing `nix build ~/flake#<Tab>`.
We can implement expansion for `~user` later if needed.
Not using wordexp(3) since that expands way too much.
This commit is contained in:
Naïm Favier 2022-02-19 14:26:34 +01:00
parent 6576f0db06
commit d69a1117a4
No known key found for this signature in database
GPG key ID: 49B07322580B7EE2
5 changed files with 21 additions and 6 deletions

View file

@ -15,7 +15,7 @@ function _complete_nix {
else else
COMPREPLY+=("$completion") COMPREPLY+=("$completion")
fi fi
done < <(NIX_GET_COMPLETIONS=$cword "${words[@]/#\~/$HOME}" 2>/dev/null) done < <(NIX_GET_COMPLETIONS=$cword "${words[@]}" 2>/dev/null)
__ltrim_colon_completions "$cur" __ltrim_colon_completions "$cur"
} }

View file

@ -1,4 +1,5 @@
#include "installables.hh" #include "installables.hh"
#include "util.hh"
#include "command.hh" #include "command.hh"
#include "attr-path.hh" #include "attr-path.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
@ -253,8 +254,7 @@ void completeFlakeRefWithFragment(
auto fragment = prefix.substr(hash + 1); auto fragment = prefix.substr(hash + 1);
auto flakeRefS = std::string(prefix.substr(0, hash)); auto flakeRefS = std::string(prefix.substr(0, hash));
// FIXME: do tilde expansion. auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath("."));
auto flakeRef = parseFlakeRef(flakeRefS, absPath("."));
auto evalCache = openEvalCache(*evalState, auto evalCache = openEvalCache(*evalState,
std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags))); std::make_shared<flake::LockedFlake>(lockFlake(*evalState, flakeRef, lockFlags)));

View file

@ -282,12 +282,13 @@ static void _completePath(std::string_view prefix, bool onlyDirs)
{ {
completionType = ctFilenames; completionType = ctFilenames;
glob_t globbuf; glob_t globbuf;
int flags = GLOB_NOESCAPE | GLOB_TILDE; int flags = GLOB_NOESCAPE;
#ifdef GLOB_ONLYDIR #ifdef GLOB_ONLYDIR
if (onlyDirs) if (onlyDirs)
flags |= GLOB_ONLYDIR; flags |= GLOB_ONLYDIR;
#endif #endif
if (glob((std::string(prefix) + "*").c_str(), flags, nullptr, &globbuf) == 0) { // using expandTilde here instead of GLOB_TILDE(_CHECK) so that ~<Tab> expands to /home/user/
if (glob((expandTilde(prefix) + "*").c_str(), flags, nullptr, &globbuf) == 0) {
for (size_t i = 0; i < globbuf.gl_pathc; ++i) { for (size_t i = 0; i < globbuf.gl_pathc; ++i) {
if (onlyDirs) { if (onlyDirs) {
auto st = stat(globbuf.gl_pathv[i]); auto st = stat(globbuf.gl_pathv[i]);
@ -295,8 +296,8 @@ static void _completePath(std::string_view prefix, bool onlyDirs)
} }
completions->add(globbuf.gl_pathv[i]); completions->add(globbuf.gl_pathv[i]);
} }
globfree(&globbuf);
} }
globfree(&globbuf);
} }
void completePath(size_t, std::string_view prefix) void completePath(size_t, std::string_view prefix)

View file

@ -200,6 +200,17 @@ std::string_view baseNameOf(std::string_view path)
} }
std::string expandTilde(std::string_view path)
{
// TODO: expand ~user ?
auto tilde = path.substr(0, 2);
if (tilde == "~/" || tilde == "~")
return getHome() + std::string(path.substr(1));
else
return std::string(path);
}
bool isInDir(std::string_view path, std::string_view dir) bool isInDir(std::string_view path, std::string_view dir)
{ {
return path.substr(0, 1) == "/" return path.substr(0, 1) == "/"

View file

@ -68,6 +68,9 @@ Path dirOf(const PathView path);
following the final `/' (trailing slashes are removed). */ following the final `/' (trailing slashes are removed). */
std::string_view baseNameOf(std::string_view path); std::string_view baseNameOf(std::string_view path);
/* Perform tilde expansion on a path. */
std::string expandTilde(std::string_view path);
/* Check whether 'path' is a descendant of 'dir'. Both paths must be /* Check whether 'path' is a descendant of 'dir'. Both paths must be
canonicalized. */ canonicalized. */
bool isInDir(std::string_view path, std::string_view dir); bool isInDir(std::string_view path, std::string_view dir);