2017-04-17 01:22:59 +00:00
|
|
|
#include "atomic_object.h"
|
2017-03-26 21:40:34 +00:00
|
|
|
#include "language_server_api.h"
|
|
|
|
#include "libclangmm/Index.h"
|
|
|
|
#include "libclangmm/TranslationUnit.h"
|
|
|
|
#include "project.h"
|
2017-05-26 06:40:38 +00:00
|
|
|
#include "threaded_queue.h"
|
2017-03-26 21:40:34 +00:00
|
|
|
#include "working_files.h"
|
|
|
|
|
|
|
|
#include <clang-c/Index.h>
|
|
|
|
|
2017-04-17 01:22:59 +00:00
|
|
|
#include <functional>
|
2017-05-26 06:40:38 +00:00
|
|
|
#include <memory>
|
2017-05-10 04:52:15 +00:00
|
|
|
#include <mutex>
|
2017-05-26 06:40:38 +00:00
|
|
|
#include <string>
|
2017-04-17 01:22:59 +00:00
|
|
|
|
2017-05-21 19:51:15 +00:00
|
|
|
// TODO: rename this file to clang_completion.h/cc
|
|
|
|
|
2017-03-26 21:40:34 +00:00
|
|
|
struct CompletionSession {
|
2017-04-20 05:01:36 +00:00
|
|
|
Project::Entry file;
|
2017-05-10 04:52:15 +00:00
|
|
|
WorkingFiles* working_files;
|
2017-05-26 06:40:38 +00:00
|
|
|
clang::Index index;
|
2017-05-10 04:52:15 +00:00
|
|
|
|
2017-05-26 06:40:38 +00:00
|
|
|
// When |tu| was last parsed.
|
|
|
|
optional<std::chrono::time_point<std::chrono::high_resolution_clock>> tu_last_parsed_at;
|
2017-03-26 21:40:34 +00:00
|
|
|
|
2017-05-26 06:40:38 +00:00
|
|
|
// Acquired when |tu| is being used.
|
|
|
|
std::mutex tu_lock;
|
2017-03-26 21:40:34 +00:00
|
|
|
|
2017-05-26 06:40:38 +00:00
|
|
|
// The active translation unit.
|
|
|
|
std::unique_ptr<clang::TranslationUnit> tu;
|
2017-03-26 21:40:34 +00:00
|
|
|
|
2017-04-26 04:03:22 +00:00
|
|
|
CompletionSession(const Project::Entry& file, WorkingFiles* working_files);
|
2017-03-26 21:40:34 +00:00
|
|
|
~CompletionSession();
|
|
|
|
};
|
|
|
|
|
2017-05-26 06:40:38 +00:00
|
|
|
struct LruSessionCache {
|
|
|
|
std::vector<std::unique_ptr<CompletionSession>> entries_;
|
|
|
|
int max_entries_;
|
|
|
|
|
|
|
|
LruSessionCache(int max_entries);
|
|
|
|
|
|
|
|
// Fetches the entry for |filename| and updates it's usage so it is less
|
|
|
|
// likely to be evicted.
|
|
|
|
CompletionSession* TryGetEntry(const std::string& filename);
|
2017-05-27 04:21:00 +00:00
|
|
|
// TryGetEntry, except the return value captures ownership.
|
|
|
|
std::unique_ptr<CompletionSession> TryTakeEntry(const std::string& fiilename);
|
2017-05-26 06:40:38 +00:00
|
|
|
// Inserts an entry. Evicts the oldest unused entry if there is no space.
|
|
|
|
void InsertEntry(std::unique_ptr<CompletionSession> session);
|
|
|
|
};
|
2017-03-26 21:40:34 +00:00
|
|
|
|
2017-05-27 04:21:00 +00:00
|
|
|
struct ClangCompleteManager {
|
2017-05-20 06:35:14 +00:00
|
|
|
using OnComplete = std::function<void(NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics)>;
|
2017-05-11 06:25:41 +00:00
|
|
|
|
2017-05-26 06:40:38 +00:00
|
|
|
struct ParseRequest {
|
|
|
|
ParseRequest(const std::string& path);
|
|
|
|
|
|
|
|
std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
|
|
|
|
std::string path;
|
|
|
|
};
|
2017-04-17 01:22:59 +00:00
|
|
|
struct CompletionRequest {
|
|
|
|
lsTextDocumentPositionParams location;
|
|
|
|
OnComplete on_complete;
|
|
|
|
};
|
2017-05-10 04:52:15 +00:00
|
|
|
|
2017-05-27 04:21:00 +00:00
|
|
|
ClangCompleteManager(Config* config, Project* project, WorkingFiles* working_files);
|
2017-03-26 21:40:34 +00:00
|
|
|
|
2017-04-17 01:22:59 +00:00
|
|
|
// Start a code completion at the given location. |on_complete| will run when
|
|
|
|
// completion results are available. |on_complete| may run on any thread.
|
2017-05-26 06:40:38 +00:00
|
|
|
void CodeComplete(const lsTextDocumentPositionParams& completion_location,
|
|
|
|
const OnComplete& on_complete);
|
|
|
|
|
|
|
|
// Notify the completion manager that |filename| has been viewed and we
|
|
|
|
// should begin preloading completion data.
|
|
|
|
void NotifyView(const std::string& filename);
|
|
|
|
// Notify the completion manager that |filename| has been edited.
|
|
|
|
void NotifyEdit(const std::string& filename);
|
|
|
|
// Notify the completion manager that |filename| has been saved. This
|
|
|
|
// triggers a reparse.
|
|
|
|
void NotifySave(const std::string& filename);
|
|
|
|
|
|
|
|
CompletionSession* TryGetSession(const std::string& filename, bool create_if_needed);
|
|
|
|
|
|
|
|
// TODO: make these configurable.
|
|
|
|
const int kMaxViewSessions = 3;
|
|
|
|
const int kMaxEditSessions = 10;
|
|
|
|
|
|
|
|
// Global state.
|
|
|
|
Config* config_;
|
|
|
|
Project* project_;
|
|
|
|
WorkingFiles* working_files_;
|
|
|
|
|
|
|
|
// Sessions which have never had a real text-edit applied, but are preloaded
|
|
|
|
// to give a fast initial experience.
|
|
|
|
LruSessionCache view_sessions_;
|
|
|
|
// Completion sessions which have been edited.
|
|
|
|
LruSessionCache edit_sessions_;
|
|
|
|
// Mutex which protects |view_sessions_| and |edit_sessions_|.
|
|
|
|
std::mutex sessions_lock_;
|
|
|
|
|
|
|
|
// Request a code completion at the given location.
|
|
|
|
AtomicObject<CompletionRequest> completion_request_;
|
|
|
|
// Parse requests. The path may already be parsed, in which case it should be
|
|
|
|
// reparsed.
|
|
|
|
ThreadedQueue<ParseRequest> parse_requests_;
|
2017-03-26 21:40:34 +00:00
|
|
|
};
|