Index: clangd/ASTManager.cpp =================================================================== --- clangd/ASTManager.cpp +++ clangd/ASTManager.cpp @@ -28,7 +28,6 @@ std::vector RemappedFiles; for (const auto &P : Docs.getAllDocuments()) { StringRef FileName = P.first; - FileName.consume_front("file://"); RemappedFiles.push_back(ASTUnit::RemappedFile( FileName, llvm::MemoryBuffer::getMemBufferCopy(P.second, FileName).release())); @@ -138,7 +137,7 @@ Diagnostics.pop_back(); // Drop trailing comma. Output.writeMessage( R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" + - File + R"(","diagnostics":[)" + Diagnostics + R"(]}})"); + Uri::unparse(File) + R"(","diagnostics":[)" + Diagnostics + R"(]}})"); } ASTManager::~ASTManager() { @@ -169,8 +168,6 @@ if (I) return I.get(); - Uri.consume_front("file://"); - std::string Error; I = tooling::CompilationDatabase::autoDetectFromSource(Uri, Error); Output.log("Failed to load compilation database: " + Twine(Error) + "\n"); @@ -182,7 +179,6 @@ tooling::CompilationDatabase *CDB = getOrCreateCompilationDatabaseForFile(Uri); - Uri.consume_front("file://"); std::vector Commands; if (CDB) { Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -29,6 +29,11 @@ namespace clang { namespace clangd { +struct Uri { + static std::string parse(llvm::StringRef uri); + static std::string unparse(llvm::StringRef file); +}; + struct TextDocumentIdentifier { /// The text document's URI. std::string uri; Index: clangd/Protocol.cpp =================================================================== --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -17,8 +17,30 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" using namespace clang::clangd; +std::string Uri::parse(llvm::StringRef uri) { + uri.consume_front("file://"); + // For Windows paths e.g. /X: + if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':') + uri.consume_front("/"); + // Make sure that file paths are in native separators + std::string Result = llvm::sys::path::convert_to_slash(uri); + return Result; +} + +std::string Uri::unparse(llvm::StringRef file) { + using namespace llvm::sys; + std::string Result = "file://"; + // For Windows paths e.g. X: + if (file.size() > 1 && file[1] == ':') + Result += "/"; + // Make sure that uri paths are with posix separators + Result += path::convert_to_slash(file, path::Style::posix); + return Result; +} + llvm::Optional TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) { TextDocumentIdentifier Result; @@ -36,7 +58,7 @@ llvm::SmallString<10> Storage; if (KeyValue == "uri") { - Result.uri = Value->getValue(Storage); + Result.uri = Uri::parse(Value->getValue(Storage)); } else if (KeyValue == "version") { // FIXME: parse version, but only for VersionedTextDocumentIdentifiers. } else { @@ -142,7 +164,7 @@ llvm::SmallString<10> Storage; if (KeyValue == "uri") { - Result.uri = Value->getValue(Storage); + Result.uri = Uri::parse(Value->getValue(Storage)); } else if (KeyValue == "languageId") { Result.languageId = Value->getValue(Storage); } else if (KeyValue == "version") { Index: clangd/clients/clangd-vscode/src/extension.ts =================================================================== --- clangd/clients/clangd-vscode/src/extension.ts +++ clangd/clients/clangd-vscode/src/extension.ts @@ -23,7 +23,12 @@ const clientOptions: vscodelc.LanguageClientOptions = { // Register the server for C/C++ files - documentSelector: ['c', 'cc', 'cpp', 'h', 'hh', 'hpp'] + documentSelector: ['c', 'cc', 'cpp', 'h', 'hh', 'hpp'], + uriConverters: { + // FIXME: implement percent decoding in clangd + code2Protocol: (uri: vscode.Uri) : string => uri.toString(true), + protocol2Code: (file: string) : vscode.Uri => vscode.Uri.file(file) + } }; const clangdClient = new vscodelc.LanguageClient('Clang Language Server', serverOptions, clientOptions);