Cache commands in complete_commands

Iterating through all directories in path to find commands
can end up quite slow, so cache the result per directory and
update it only if the directory modification time changed.
This commit is contained in:
Maxime Coste 2014-04-24 19:08:05 +01:00
parent 46d5e72960
commit 192e0c33f9

View File

@ -358,6 +358,13 @@ std::vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
dir_end = i; dir_end = i;
} }
struct CommandCache
{
timespec mtime = {};
std::vector<String> commands;
};
static std::unordered_map<String, CommandCache> command_cache;
std::vector<String> path; std::vector<String> path;
if (dir_end != -1) if (dir_end != -1)
{ {
@ -373,6 +380,10 @@ std::vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
if (not dirname.empty() and dirname.back() != '/') if (not dirname.empty() and dirname.back() != '/')
dirname += '/'; dirname += '/';
struct stat st;
if (stat(dirname.substr(0_byte, dirname.length() - 1).c_str(), &st))
continue;
auto filter = [&](const dirent& entry) { auto filter = [&](const dirent& entry) {
struct stat st; struct stat st;
if (stat((dirname + entry.d_name).c_str(), &st)) if (stat((dirname + entry.d_name).c_str(), &st))
@ -382,8 +393,18 @@ std::vector<String> complete_command(StringView prefix, ByteCount cursor_pos)
| (st.st_mode & S_IXOTH); | (st.st_mode & S_IXOTH);
return S_ISREG(st.st_mode) and executable; return S_ISREG(st.st_mode) and executable;
}; };
auto completion = list_files(prefix, dirname, filter);
std::move(completion.begin(), completion.end(), std::back_inserter(res)); auto& cache = command_cache[dirname];
if (memcmp(&cache.mtime, &st.st_mtim, sizeof(struct timespec)) != 0)
{
cache.mtime = st.st_mtim;
cache.commands = list_files("", dirname, filter);
}
for (auto& cmd : cache.commands)
{
if (prefix_match(cmd, fileprefix))
res.push_back(cmd);
}
} }
std::sort(res.begin(), res.end()); std::sort(res.begin(), res.end());
auto it = std::unique(res.begin(), res.end()); auto it = std::unique(res.begin(), res.end());