diff --git a/src/frontends/lean/completion.cpp b/src/frontends/lean/completion.cpp index c6a07f8e08..3a3b180d4e 100644 --- a/src/frontends/lean/completion.cpp +++ b/src/frontends/lean/completion.cpp @@ -165,6 +165,59 @@ std::vector get_decl_completions(std::string const & pattern, environment return completions; } +void search_decls(std::string const & pattern, std::vector> const & envs, options const & opts, + std::vector & completions) { + unsigned max_results = get_auto_completion_max_results(opts); + unsigned max_errors = get_fuzzy_match_max_errors(pattern.size()); + name_map> name2env; + std::vector> exact_matches; + std::vector> selected; + bitap_fuzzy_search matcher(pattern, max_errors); + + for (auto & env_file : envs) { + auto & env = env_file.second; + env.for_each_declaration([&](declaration const & d) { + if (name2env.find(d.get_name())) return; + name2env.insert(d.get_name(), env_file); + if (is_projection(env, d.get_name())) { + auto s_name = d.get_name().get_prefix(); + } + if (is_internal_name(d.get_name())) { + return; + } + if (auto it = exact_prefix_match(env, pattern, d)) { + exact_matches.emplace_back(*it, d.get_name()); + } else { + std::string text = d.get_name().to_string(); + if (matcher.match(text)) + selected.emplace_back(text, d.get_name()); + } + }); + } + unsigned num_results = 0; + if (!exact_matches.empty()) { + std::sort(exact_matches.begin(), exact_matches.end(), + [](pair const & p1, pair const & p2) { + return p1.first.size() < p2.first.size(); + }); + for (pair const & p : exact_matches) { + auto j = serialize_decl(p.first, p.second, name2env.find(p.second)->second, opts); + if (!j["source"].count("file")) + j["source"]["file"] = name2env.find(p.second)->first; + completions.push_back(j); + num_results++; + if (num_results >= max_results) + break; + } + } + filter_completions(pattern, selected, completions, max_results - num_results, [&](name const & n) { + auto j = serialize_decl(n, name2env.find(n)->second, opts); + if (!j["source"].count("file")) + j["source"]["file"] = name2env.find(n)->first; + return j; + }); +} + std::vector get_field_completions(name const & s, std::string const & pattern, environment const & env, options const & opts) { std::vector completions; diff --git a/src/frontends/lean/completion.h b/src/frontends/lean/completion.h index 4b57813d55..feb825a919 100644 --- a/src/frontends/lean/completion.h +++ b/src/frontends/lean/completion.h @@ -24,6 +24,9 @@ std::vector get_interactive_tactic_completions(std::string const & pattern std::vector get_attribute_completions(std::string const & pattern, environment const & env, options const & opts); std::vector get_namespace_completions(std::string const & pattern, environment const & env, options const & opts); +void search_decls(std::string const & pattern, std::vector> const & envs, + options const & opts, std::vector & completions); + void initialize_completion(); void finalize_completion(); } diff --git a/src/library/module_mgr.cpp b/src/library/module_mgr.cpp index f9fe34bd0a..76dc43ba06 100644 --- a/src/library/module_mgr.cpp +++ b/src/library/module_mgr.cpp @@ -19,6 +19,28 @@ Author: Gabriel Ebner namespace lean { +environment module_info::get_latest_env() const { + if (m_snapshots) { + auto snap = *m_snapshots; + while (snap.m_next) { + if (auto next = peek(snap.m_next)) { + snap = *next; + } else { + break; + } + } + if (auto parser_snap = snap.m_snapshot_at_end) { + return parser_snap->m_env; + } + } + if (auto res = peek(m_result)) { + if (auto env = peek(res->m_loaded_module->m_env)) { + return *env; + } + } + return environment(); +} + void module_mgr::mark_out_of_date(module_id const & id) { for (auto & mod : m_modules) { if (!mod.second || mod.second->m_out_of_date) continue; @@ -371,6 +393,19 @@ std::vector module_mgr::get_direct_imports(module_id const & id, st return imports; } +std::vector> module_mgr::get_all_modules() { + unique_lock lock(m_mutex); + + std::vector> mods; + for (auto & mod : m_modules) { + if (mod.second) { + mods.push_back(mod.second); + } + } + + return mods; +} + void module_mgr::cancel_all() { for (auto & m : m_modules) { if (auto mod = m.second) { diff --git a/src/library/module_mgr.h b/src/library/module_mgr.h index 0ba6aea131..b9955982eb 100644 --- a/src/library/module_mgr.h +++ b/src/library/module_mgr.h @@ -58,6 +58,8 @@ struct module_info { environment const & get_produced_env() const { return get(get(m_result).m_loaded_module->m_env); } + + environment get_latest_env() const; }; class module_vfs { @@ -107,6 +109,8 @@ public: std::shared_ptr get_module(module_id const &); + std::vector> get_all_modules(); + void cancel_all(); void set_use_snapshots(bool use_snapshots) { m_use_snapshots = use_snapshots; } diff --git a/src/shell/server.cpp b/src/shell/server.cpp index 39359ee198..1af2bbf692 100644 --- a/src/shell/server.cpp +++ b/src/shell/server.cpp @@ -22,6 +22,7 @@ Authors: Gabriel Ebner, Leonardo de Moura, Sebastian Ullrich #include "frontends/lean/parser.h" #include "frontends/lean/info_manager.h" #include "frontends/lean/interactive.h" +#include "frontends/lean/completion.h" #include "shell/server.h" namespace lean { @@ -427,6 +428,8 @@ void server::handle_request(server::cmd_req const & req) { handle_async_response(req, handle_complete(req)); } else if (command == "info") { handle_async_response(req, handle_info(req)); + } else if (command == "search") { + send_msg(handle_search(req)); } else if (command == "roi") { send_msg(handle_roi(req)); } else if (command == "sleep") { @@ -602,6 +605,23 @@ task server::handle_info(server::cmd_req const & req) { .set_cancellation_token(m_bg_task_ctok).build(); } +server::cmd_res server::handle_search(server::cmd_req const & req) { + std::string query = req.m_payload.at("query"); + + std::vector> envs_to_search; + for (auto & mod : m_mod_mgr->get_all_modules()) { + envs_to_search.emplace_back(mod->m_mod, mod->get_latest_env()); + } + + std::vector results; + search_decls(query, envs_to_search, m_ios.get_options(), results); + + json j; + j["results"] = results; + + return cmd_res(req.m_seq_num, j); +} + std::tuple server::load_module(module_id const & id, bool can_use_olean) { if (m_open_files.count(id)) { auto & ef = m_open_files[id]; diff --git a/src/shell/server.h b/src/shell/server.h index 9bd34c69eb..9434a91fbb 100644 --- a/src/shell/server.h +++ b/src/shell/server.h @@ -97,6 +97,7 @@ class server : public module_vfs { cmd_res handle_sync(cmd_req const & req); task handle_complete(cmd_req const & req); task handle_info(cmd_req const & req); + cmd_res handle_search(cmd_req const & req); cmd_res handle_roi(cmd_req const & req); json autocomplete(std::shared_ptr const & mod_info, bool skip_completions, pos_info const & pos);