Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/clang_tu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ std::string PathFromFileEntry(const FileEntry &file) {
if (Name.empty())
Name = file.getName();
std::string ret = NormalizePath(Name);
// Resolve /usr/include/c++/7.3.0 symlink.
if (!llvm::any_of(g_config->workspaceFolders, [&](const std::string &root) {
return StringRef(ret).startswith(root);
})) {
// Resolve symlinks outside of workspace folders, e.g. /usr/include/c++/7.3.0
bool in_folder = false;
for (auto &[root, real] : g_config->workspaceFolders)
if (real.size() && StringRef(ret).startswith(real)) {
ret = root + ret.substr(real.size());
in_folder = true;
break;
}
if (!in_folder) {
SmallString<256> dest;
llvm::sys::fs::real_path(ret, dest);
ret = llvm::sys::path::convert_to_slash(dest.str());
Expand Down
2 changes: 1 addition & 1 deletion src/config.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ initialization options specified by the client. For example, in shell syntax:
struct Config {
// **Not available for configuration**
std::string fallbackFolder;
std::vector<std::string> workspaceFolders;
std::vector<std::pair<std::string, std::string>> workspaceFolders;
// If specified, this option overrides compile_commands.json and this
// external command will be executed with an option |projectRoot|.
// The initialization options will be provided as stdin.
Expand Down
6 changes: 6 additions & 0 deletions src/lsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.

#include "log.hh"

#include <llvm/ADT/StringRef.h>

#include <rapidjson/document.h>

#include <algorithm>
Expand Down Expand Up @@ -131,6 +133,10 @@ std::string DocumentUri::GetPath() const {
ret[0] = toupper(ret[0]);
}
#endif
if (g_config)
for (auto &[root, real] : g_config->workspaceFolders)
if (real.size() && llvm::StringRef(ret).startswith(real))
return root + ret.substr(real.size());
return ret;
}

Expand Down
28 changes: 22 additions & 6 deletions src/messages/initialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -337,19 +337,35 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
// Set project root.
EnsureEndsInSlash(project_path);
g_config->fallbackFolder = project_path;
auto &workspaceFolders = g_config->workspaceFolders;
auto Real = [](const std::string &path) {
SmallString<256> real;
sys::fs::real_path(path, real);
return sys::path::convert_to_slash(real) + '/';
};
for (const WorkspaceFolder &wf : param.workspaceFolders) {
std::string path = wf.uri.GetPath();
EnsureEndsInSlash(path);
g_config->workspaceFolders.push_back(path);
LOG_S(INFO) << "add workspace folder " << wf.name << ": " << path;
std::string real = Real(path);
workspaceFolders.emplace_back(path, path == real ? "" : real);
}
if (workspaceFolders.empty()) {
std::string real = Real(project_path);
workspaceFolders.emplace_back(project_path,
project_path == real ? "" : real);
}
if (param.workspaceFolders.empty())
g_config->workspaceFolders.push_back(project_path);
llvm::sort(workspaceFolders,
[](auto &l, auto &r) { return l.first.size() > r.first.size(); });
for (auto &[folder, real] : workspaceFolders)
if (real.empty())
LOG_S(INFO) << "workspace folder: " << folder;
else
LOG_S(INFO) << "workspace folder: " << folder << " -> " << real;

if (g_config->cache.directory.empty())
g_config->cache.retainInMemory = 1;
else if (!g_config->cache.hierarchicalPath)
for (const std::string &folder : g_config->workspaceFolders) {
for (auto &[folder, _] : workspaceFolders) {
// Create two cache directories for files inside and outside of the
// project.
std::string escaped = EscapeFileName(folder.substr(0, folder.size() - 1));
Expand All @@ -358,7 +374,7 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
}

idx::Init();
for (const std::string &folder : g_config->workspaceFolders)
for (auto &[folder, _] : workspaceFolders)
m->project->Load(folder);

// Start indexer threads. Start this after loading the project, as that
Expand Down
29 changes: 21 additions & 8 deletions src/messages/workspace.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ limitations under the License.

#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>

#include <algorithm>
Expand All @@ -35,7 +36,7 @@ namespace ccls {
REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName);

void MessageHandler::workspace_didChangeConfiguration(EmptyParam &) {
for (const std::string &folder : g_config->workspaceFolders)
for (auto &[folder, _] : g_config->workspaceFolders)
project->Load(folder);
project->Index(wfiles, RequestId());

Expand Down Expand Up @@ -82,7 +83,8 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
std::string root = wf.uri.GetPath();
EnsureEndsInSlash(root);
LOG_S(INFO) << "delete workspace folder " << wf.name << ": " << root;
auto it = llvm::find(g_config->workspaceFolders, root);
auto it = llvm::find_if(g_config->workspaceFolders,
[&](auto &folder) { return folder.first == root; });
if (it != g_config->workspaceFolders.end()) {
g_config->workspaceFolders.erase(it);
{
Expand All @@ -92,13 +94,24 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
project->root2folder.erase(root);
}
}
auto &workspaceFolders = g_config->workspaceFolders;
for (const WorkspaceFolder &wf : param.event.added) {
std::string root = wf.uri.GetPath();
EnsureEndsInSlash(root);
LOG_S(INFO) << "add workspace folder " << wf.name << ": " << root;
g_config->workspaceFolders.push_back(root);
project->Load(root);
}
std::string folder = wf.uri.GetPath();
EnsureEndsInSlash(folder);
SmallString<256> buf;
sys::fs::real_path(folder, buf);
auto real = llvm::sys::path::convert_to_slash(buf) + '/';
if (folder == real)
real.clear();
LOG_S(INFO) << "add workspace folder " << wf.name << ": "
<< (real.empty() ? folder : folder + " -> " + real);
workspaceFolders.emplace_back();
auto it = workspaceFolders.end() - 1;
for (; it != workspaceFolders.begin() && folder < it[-1].first; --it)
*it = it[-1];
*it = {folder, real};
project->Load(folder);
}

project->Index(wfiles, RequestId());

Expand Down
4 changes: 2 additions & 2 deletions src/pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ std::string AppendSerializationFormat(const std::string &base) {
}
}

std::string GetCachePath(const std::string &src) {
std::string GetCachePath(std::string src) {
if (g_config->cache.hierarchicalPath) {
std::string ret =
g_config->cache.directory + (src[0] == '/' ? src.substr(1) : src);
Expand All @@ -154,7 +154,7 @@ std::string GetCachePath(const std::string &src) {
#endif
return ret;
}
for (auto &root : g_config->workspaceFolders)
for (auto &[root, _] : g_config->workspaceFolders)
if (StringRef(src).startswith(root)) {
auto len = root.size();
return g_config->cache.directory +
Expand Down