From 192e0c33f9a7f80d20fe8569cf879162a5332efa Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 24 Apr 2014 19:08:05 +0100 Subject: [PATCH] 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. --- src/file.cc | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/file.cc b/src/file.cc index 7fb6bce7..5d7326b5 100644 --- a/src/file.cc +++ b/src/file.cc @@ -358,6 +358,13 @@ std::vector complete_command(StringView prefix, ByteCount cursor_pos) dir_end = i; } + struct CommandCache + { + timespec mtime = {}; + std::vector commands; + }; + static std::unordered_map command_cache; + std::vector path; if (dir_end != -1) { @@ -373,6 +380,10 @@ std::vector complete_command(StringView prefix, ByteCount cursor_pos) if (not dirname.empty() and dirname.back() != '/') dirname += '/'; + struct stat st; + if (stat(dirname.substr(0_byte, dirname.length() - 1).c_str(), &st)) + continue; + auto filter = [&](const dirent& entry) { struct stat st; if (stat((dirname + entry.d_name).c_str(), &st)) @@ -382,8 +393,18 @@ std::vector complete_command(StringView prefix, ByteCount cursor_pos) | (st.st_mode & S_IXOTH); 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()); auto it = std::unique(res.begin(), res.end());