Files
clice/src/Server/Command.cpp
ykiko c082458fb1 1. Make resource dir unique and global.
2. Use our custom CDB loader.
2024-12-10 16:15:50 +08:00

119 lines
3.4 KiB
C++

#include "Server/Command.h"
#include "Server/Config.h"
#include "Server/Logger.h"
namespace clice {
void CommandManager::update(llvm::StringRef dir) {
llvm::SmallString<128> path;
path::append(path, dir, "compile_commands.json");
auto buffer = llvm::MemoryBuffer::getFile(path);
if(!buffer) {
log::warn("Failed to read compile_commands.json from {}, because {}",
dir,
buffer.getError().message());
return;
}
auto json = json::parse(buffer.get()->getBuffer());
if(!json) {
log::warn("Failed to parse json file at {}, because {}", path, json.takeError());
return;
}
if(!json->getAsArray()) {
log::warn("Invalid JSON format at {}, Compilation Database requires Array, but get {}",
path,
refl::enum_name(json->kind()));
return;
}
auto& CDB = CDBs[dir];
/// Clear old commands.
/// FIXME: it would be better to have cache in some way.
CDB.clear();
for(auto& value: *json->getAsArray()) {
auto element = value.getAsObject();
if(!element) {
log::warn("Invalid JSON format at {}, Compilation Database requires Object, but get {}",
path,
refl::enum_name(value.kind()));
continue;
}
/// Source file path.
llvm::SmallString<128> path;
auto file = element->getString("file");
if(!file) {
log::warn("the element in {} does not have a file field",
path,
refl::enum_name(value.kind()));
continue;
}
if(path::is_relative(file.value())) {
auto working = element->getString("directory");
if(!working) {
log::warn(
"Invalid JSON format at {}, {} is relative path, but directory is not provided",
path,
file.value());
}
path::append(path, working.value(), file.value());
} else {
path::append(path, file.value());
}
/// Command to compile the source file.
llvm::SmallString<1024> rawCommand;
if(auto command = element->getString("command")) {
rawCommand = command.value();
} else if(auto arguments = element->getArray("arguments")) {
/// FIXME:
std::terminate();
} else {
log::warn(
"Invalid JSON format, the element in {} does not have a command or arguments field",
path,
refl::enum_name(value.kind()));
continue;
}
CDB[path].emplace_back(rawCommand.str());
}
log::info("Compilation Database at {} is up-to-date", dir);
}
llvm::StringRef CommandManager::lookupFirst(llvm::StringRef file) {
for(auto& [dir, cdb]: CDBs) {
auto iter = cdb.find(file);
if(iter != cdb.end()) {
return iter->second.front();
}
}
return {};
}
llvm::ArrayRef<std::string> CommandManager::lookup(llvm::StringRef file) {
for(auto& [dir, cdb]: CDBs) {
/// FIXME: currently we directly return the first match.
/// it is better to provide a callback to handle all matches.
auto iter = cdb.find(file);
if(iter != cdb.end()) {
return iter->second;
}
}
return {};
}
} // namespace clice