#include "LibLsp/lsp/working_files.h" #include #include #include #include "LibLsp/lsp/utils.h" #include #include "LibLsp/lsp/AbsolutePath.h" using namespace lsp; struct WorkingFilesData { std::map > files; std::mutex files_mutex; // Protects |d_ptr->files|. }; WorkingFile::WorkingFile(WorkingFiles& _parent, const AbsolutePath& filename, const std::string& buffer_content) : filename(filename), directory(filename), parent(_parent), counter(0), buffer_content(buffer_content) { directory = Directory(GetDirName(filename.path)); } WorkingFile::WorkingFile(WorkingFiles& _parent, const AbsolutePath& filename, std::string&& buffer_content) : filename(filename), directory(filename), parent(_parent), counter(0), buffer_content(buffer_content) { directory = Directory(GetDirName(filename.path)); } WorkingFiles::WorkingFiles():d_ptr(new WorkingFilesData()) { } WorkingFiles::~WorkingFiles() { delete d_ptr; } void WorkingFiles::CloseFilesInDirectory(const std::vector& directories) { std::lock_guard lock(d_ptr->files_mutex); std::vector files_to_be_delete; for(auto& it : d_ptr->files) { for (auto& dir : directories) { if (it.second->directory == dir) { files_to_be_delete.emplace_back(it.first); } } } for(auto& it : files_to_be_delete) { d_ptr->files.erase(it); } } std::shared_ptr WorkingFiles::GetFileByFilename(const AbsolutePath& filename) { std::lock_guard lock(d_ptr->files_mutex); return GetFileByFilenameNoLock(filename); } std::shared_ptr WorkingFiles::GetFileByFilenameNoLock( const AbsolutePath& filename) { const auto findIt = d_ptr->files.find(filename); if ( findIt != d_ptr->files.end()) { return findIt->second; } return nullptr; } std::shared_ptr WorkingFiles::OnOpen( lsTextDocumentItem& open) { std::lock_guard lock(d_ptr->files_mutex); AbsolutePath filename = open.uri.GetAbsolutePath(); // The file may already be open. if (auto file = GetFileByFilenameNoLock(filename)) { file->version = open.version; file->buffer_content.swap(open.text); return file; } const auto& it = d_ptr->files.insert({ filename,std::make_shared(*this,filename, std::move(open.text)) }); return it.first->second; } std::shared_ptr WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) { std::lock_guard lock(d_ptr->files_mutex); AbsolutePath filename = change.textDocument.uri.GetAbsolutePath(); auto file = GetFileByFilenameNoLock(filename); if (!file) { return {}; } if (change.textDocument.version) file->version = *change.textDocument.version; file->counter.fetch_add(1, std::memory_order_relaxed); for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) { // Per the spec replace everything if the rangeLength and range are not set. // See https://github.com/Microsoft/language-server-protocol/issues/9. if (!diff.range) { file->buffer_content = diff.text; } else { int start_offset = GetOffsetForPosition(diff.range->start, file->buffer_content); // Ignore TextDocumentContentChangeEvent.rangeLength which causes trouble // when UTF-16 surrogate pairs are used. int end_offset = GetOffsetForPosition(diff.range->end, file->buffer_content); file->buffer_content.replace(file->buffer_content.begin() + start_offset, file->buffer_content.begin() + end_offset, diff.text); } } return file; } bool WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) { std::lock_guard lock(d_ptr->files_mutex); AbsolutePath filename = close.uri.GetAbsolutePath(); const auto findIt = d_ptr->files.find(filename); if( findIt != d_ptr->files.end()) { d_ptr->files.erase(findIt); return true; } return false; } std::shared_ptr WorkingFiles::OnSave(const lsTextDocumentIdentifier& _save) { std::lock_guard lock(d_ptr->files_mutex); AbsolutePath filename = _save.uri.GetAbsolutePath(); const auto findIt = d_ptr->files.find(filename); if (findIt != d_ptr->files.end()) { std::shared_ptr& file = findIt->second; lsp::WriteToFile(file->filename, file->GetContentNoLock()); return findIt->second; } return {}; } bool WorkingFiles::GetFileBufferContent(std::shared_ptr&file, std::string& out) { std::lock_guard lock(d_ptr->files_mutex); if (file) { out = file->buffer_content; return true; } return false; } bool WorkingFiles::GetFileBufferContent(std::shared_ptr& file, std::wstring& out) { std::lock_guard lock(d_ptr->files_mutex); if (file) { out = lsp::s2ws(file->buffer_content); return true; } return false; } void WorkingFiles::Clear() { std::lock_guard lock(d_ptr->files_mutex); d_ptr->files.clear(); }