This commit is contained in:
Jacob Dufault 2017-03-04 18:16:23 -08:00
parent 2a08552265
commit 8fb0fb816c
7 changed files with 1727 additions and 125 deletions

View File

@ -1,11 +1,21 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <thread>
#include "compilation_database_loader.h" #include "compilation_database_loader.h"
#include "indexer.h" #include "indexer.h"
#include "ipc.h" #include "ipc.h"
#include "query.h" #include "query.h"
#include "language_server_api.h"
#include <rapidjson/istreamwrapper.h>
#include <rapidjson/ostreamwrapper.h>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#endif
bool ParsePreferredSymbolLocation(const std::string& content, PreferredSymbolLocation* obj) { bool ParsePreferredSymbolLocation(const std::string& content, PreferredSymbolLocation* obj) {
#define PARSE_AS(name, string) \ #define PARSE_AS(name, string) \
@ -96,7 +106,7 @@ indexer.exe --index-file /work2/chrome/src/chrome/foo.cc
*/ */
struct IpcMessage_IsAlive : public BaseIpcMessage { struct IpcMessage_IsAlive : public BaseIpcMessage<IpcMessage_IsAlive> {
static IpcMessageId id; static IpcMessageId id;
}; };
@ -109,7 +119,12 @@ IpcMessageId IpcMessage_IsAlive::id = "IsAlive";
struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage {
struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage<IpcMessage_DocumentSymbolsRequest> {
std::string document; std::string document;
// BaseIpcMessage: // BaseIpcMessage:
@ -123,58 +138,8 @@ struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage {
}; };
IpcMessageId IpcMessage_DocumentSymbolsRequest::id = "IpcMessage_DocumentSymbolsRequest"; IpcMessageId IpcMessage_DocumentSymbolsRequest::id = "IpcMessage_DocumentSymbolsRequest";
struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage<IpcMessage_DocumentSymbolsResponse> {
// Keep all types in the language_server_api namespace in sync with language server spec. std::vector<language_server_api::SymbolInformation> symbols;
namespace language_server_api {
using DocumentUri = std::string; // TODO
struct Position {
// Note: these are 0-based.
int line;
int character;
};
struct Range {
Position start;
Position end;
};
struct Location {
DocumentUri uri;
Range range;
};
enum class SymbolKind : int {
File = 1,
Module = 2,
Namespace = 3,
Package = 4,
Class = 5,
Method = 6,
Property = 7,
Field = 8,
Constructor = 9,
Enum = 10,
Interface = 11,
Function = 12,
Variable = 13,
Constant = 14,
String = 15,
Number = 16,
Boolean = 17,
Array = 18
};
struct SymbolInfo {
std::string name;
SymbolKind kind;
Location location;
std::string containerName;
};
}
struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage {
std::vector<language_server_api::SymbolInfo> symbols;
// BaseIpcMessage: // BaseIpcMessage:
static IpcMessageId id; static IpcMessageId id;
@ -185,22 +150,22 @@ IpcMessageId IpcMessage_DocumentSymbolsResponse::id = "IpcMessage_DocumentSymbol
void QueryDbMain() {
void IndexerServerMain() {
IpcServer ipc("languageserver"); IpcServer ipc("languageserver");
while (true) { while (true) {
std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc.TakeMessages(); std::vector<std::unique_ptr<BaseIpcMessageElided>> messages = ipc.TakeMessages();
std::cout << "Server has " << messages.size() << " messages" << std::endl;
for (auto& message : messages) { for (auto& message : messages) {
if (message->runtime_id == IpcMessage_IsAlive::id) { std::cout << "Processing message " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
if (message->runtime_id() == IpcMessage_IsAlive::id) {
IpcMessage_IsAlive response; IpcMessage_IsAlive response;
ipc.SendToClient(0, &response); // todo: make non-blocking ipc.SendToClient(0, &response); // todo: make non-blocking
break; break;
} }
else { else {
std::cerr << "Unhandled IPC message with kind " << message->runtime_id << " (hash " << message->hashed_runtime_id << ")" << std::endl; std::cerr << "Unhandled IPC message with kind " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
exit(1); exit(1);
break; break;
} }
@ -226,21 +191,130 @@ void LanguageServerStdinToServerDispatcher(IpcClient& ipc) {
} }
} }
void ParseRpc(const std::string& method, const rapidjson::GenericValue<rapidjson::UTF8<>>& params) {
}
std::unique_ptr<language_server_api::InMessage> ParseMessage() {
int content_length = -1;
int iteration = 0;
while (true) {
if (++iteration > 10) {
assert(false && "bad parser state");
exit(1);
}
std::string line;
std::getline(std::cin, line);
//std::cin >> line;
if (line.compare(0, 14, "Content-Length") == 0) {
content_length = atoi(line.c_str() + 16);
}
if (line == "\r")
break;
}
assert(content_length >= 0);
std::string content;
content.reserve(content_length);
for (int i = 0; i < content_length; ++i) {
char c;
std::cin >> c;
content += c;
}
rapidjson::Document document;
document.Parse(content.c_str(), content_length);
assert(!document.HasParseError());
return language_server_api::MessageRegistry::instance()->Parse(document);
/*
std::string id;
if (document["id"].IsString())
id = document["id"].GetString();
else
id = std::to_string(document["id"].GetInt());
std::string method = document["method"].GetString();
auto& params = document["params"];
// Send initialize response.
{
std::string content =
R"foo({
"jsonrpc": "2.0",
"id": 0,
"result": {
"capabilities": {
"documentSymbolProvider": true
}
}
})foo";
std::cout << "Content-Length: " << content.size();
std::cout << (char)13 << char(10) << char(13) << char(10);
std::cout << content;
}
*/
}
// Main loop for the language server. |ipc| is connected to // Main loop for the language server. |ipc| is connected to
// a server. // a server.
void LanguageServerLoop(IpcClient& ipc) { void LanguageServerLoop(IpcClient* ipc) {
using namespace language_server_api;
while (true) { while (true) {
std::string input; std::unique_ptr<InMessage> message = ParseMessage();
std::cin >> input;
std::cout << "got input " << input << std::endl << std::endl; // Message parsing can fail if we don't recognize the method.
if (!message)
continue;
if (input == "references") { std::cerr << "[info]: Got message of type " << MethodIdToString(message->method_id) << std::endl;
switch (message->method_id) {
case MethodId::Initialize:
{
// TODO: response should take id as input.
// TODO: message should not have top-level id.
auto response = Out_InitializeResponse();
response.id = message->id.value();
response.result.capabilities.documentSymbolProvider = true;
response.Send();
break;
}
case MethodId::TextDocumentDocumentSymbol:
{
auto response = Out_DocumentSymbolResponse();
response.id = message->id.value();
for (int i = 0; i < 2500; ++i) {
SymbolInformation info;
info.containerName = "fooContainer";
info.kind = language_server_api::SymbolKind::Field;
info.location.range.start.line = 5;
info.location.range.end.character = 20;
info.location.range.end.line = 5;
info.location.range.end.character = 25;
info.name = "Foobar";
response.result.push_back(info);
}
response.Send();
break;
}
} }
} }
} }
void LanguageServerMain() { void LanguageServerMain() {
IpcClient ipc("languageserver", 0); IpcClient ipc("languageserver", 0);
@ -255,23 +329,44 @@ void LanguageServerMain() {
std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::this_thread::sleep_for(std::chrono::milliseconds(20));
// Check if we got an IsAlive message back. // Check if we got an IsAlive message back.
std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc.TakeMessages(); std::vector<std::unique_ptr<BaseIpcMessageElided>> messages = ipc.TakeMessages();
bool has_server = false; bool has_server = false;
for (auto& message : messages) { for (auto& message : messages) {
if (message->runtime_id == IpcMessage_IsAlive::id) { if (message->runtime_id() == IpcMessage_IsAlive::id) {
has_server = true; has_server = true;
break; break;
} }
} }
// No server is running. Start it. // No server is running. Start it.
if (!has_server) { //if (!has_server) {
std::cerr << "Unable to detect running indexer server" << std::endl; // std::cerr << "Unable to detect running indexer server" << std::endl;
exit(1); // exit(1);
} //}
std::cout << "Found indexer server" << std::endl; std::thread stdio_reader(&LanguageServerLoop, &ipc);
LanguageServerLoop(ipc);
//std::cout << "Found indexer server" << std::endl;
//LanguageServerLoop(ipc);
// TODO: This is used for debugging, so we can attach to the client.
//std::cout << "garbagelkadklasldk" << std::endl;
bool should_break = true;
while (should_break)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
//std::this_thread::sleep_for(std::chrono::seconds(4));
//std::cout.flush();
/*
language_server_api::ShowMessageOutNotification show;
show.type = language_server_api::MessageType::Info;
show.message = "hello";
show.Send();
*/
} }
@ -348,19 +443,40 @@ void IpcMessage_CreateIndex::Deserialize(Reader& reader) {
#endif #endif
int main(int argc, char** argv) { int main(int argc, char** argv) {
// We need to write to stdout in binary mode because in Windows, writing
// \n will implicitly write \r\n. Language server API will ignore a
// \r\r\n split request.
#ifdef _WIN32
_setmode(_fileno(stdout), O_BINARY);
_setmode(_fileno(stdin), O_BINARY);
#endif
std::cerr << "Starting language server" << std::endl;
IpcRegistry::instance()->Register<IpcMessage_IsAlive>(); IpcRegistry::instance()->Register<IpcMessage_IsAlive>();
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsRequest>(); IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsRequest>();
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsResponse>(); IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsResponse>();
language_server_api::MessageRegistry::instance()->Register<language_server_api::In_CancelRequest>();
if (argc == 2) language_server_api::MessageRegistry::instance()->Register<language_server_api::In_InitializeRequest>();
LanguageServerMain(); language_server_api::MessageRegistry::instance()->Register<language_server_api::In_InitializedNotification>();
else language_server_api::MessageRegistry::instance()->Register<language_server_api::In_DocumentSymbolRequest>();
IndexerServerMain();
return 0;
std::unordered_map<std::string, std::string> options = ParseOptions(argc, argv); std::unordered_map<std::string, std::string> options = ParseOptions(argc, argv);
if (HasOption(options, "--language-server")) {
LanguageServerMain();
return 0;
}
if (HasOption(options, "--querydb")) {
QueryDbMain();
return 0;
}
LanguageServerMain();
return 0;
if (argc == 1 || options.find("--help") != options.end()) { if (argc == 1 || options.find("--help") != options.end()) {
std::cout << R"help(clang-indexer help: std::cout << R"help(clang-indexer help:

41
ipc.cc
View File

@ -24,27 +24,14 @@ void JsonMessage::SetPayload(size_t payload_size, const char* payload) {
memcpy(payload_dest, payload, payload_size); memcpy(payload_dest, payload, payload_size);
} }
BaseIpcMessage::BaseIpcMessage() { void BaseIpcMessageElided::Serialize(Writer& writer) {}
assert(!runtime_id_.empty() && "Message is not registered using IpcRegistry::RegisterAllocator");
runtime_id = runtime_id_; void BaseIpcMessageElided::Deserialize(Reader& reader) {}
hashed_runtime_id = hashed_runtime_id_;
}
BaseIpcMessage::~BaseIpcMessage() {}
void BaseIpcMessage::Serialize(Writer& writer) {}
void BaseIpcMessage::Deserialize(Reader& reader) {}
IpcMessageId BaseIpcMessage::runtime_id_;
int BaseIpcMessage::hashed_runtime_id_ = -1;
IpcRegistry* IpcRegistry::instance_ = nullptr; IpcRegistry* IpcRegistry::instance_ = nullptr;
std::unique_ptr<BaseIpcMessage> IpcRegistry::Allocate(int id) { std::unique_ptr<BaseIpcMessageElided> IpcRegistry::Allocate(int id) {
return std::unique_ptr<BaseIpcMessage>((*allocators)[id]()); return std::unique_ptr<BaseIpcMessageElided>((*allocators)[id]());
} }
IpcDirectionalChannel::IpcDirectionalChannel(const std::string& name) { IpcDirectionalChannel::IpcDirectionalChannel(const std::string& name) {
@ -57,7 +44,7 @@ IpcDirectionalChannel::~IpcDirectionalChannel() {
delete[] local_block; delete[] local_block;
} }
void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) { void IpcDirectionalChannel::PushMessage(BaseIpcMessageElided* message) {
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output); rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
writer.SetFormatOptions( writer.SetFormatOptions(
@ -65,6 +52,8 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) {
writer.SetIndent(' ', 2); writer.SetIndent(' ', 2);
message->Serialize(writer); message->Serialize(writer);
//std::cout << "Sending message with id " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
size_t payload_size = strlen(output.GetString()); size_t payload_size = strlen(output.GetString());
assert(payload_size < shmem_size && "Increase shared memory size, payload will never fit"); assert(payload_size < shmem_size && "Increase shared memory size, payload will never fit");
@ -86,7 +75,7 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) {
if ((*shared->shared_bytes_used + sizeof(JsonMessage) + payload_size) >= shmem_size) if ((*shared->shared_bytes_used + sizeof(JsonMessage) + payload_size) >= shmem_size)
continue; continue;
get_free_message()->message_id = message->hashed_runtime_id; get_free_message()->message_id = message->hashed_runtime_id();
get_free_message()->SetPayload(payload_size, output.GetString()); get_free_message()->SetPayload(payload_size, output.GetString());
*shared->shared_bytes_used += sizeof(JsonMessage) + get_free_message()->payload_size; *shared->shared_bytes_used += sizeof(JsonMessage) + get_free_message()->payload_size;
@ -97,7 +86,7 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessage* message) {
} }
std::vector<std::unique_ptr<BaseIpcMessage>> IpcDirectionalChannel::TakeMessages() { std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcDirectionalChannel::TakeMessages() {
size_t remaining_bytes = 0; size_t remaining_bytes = 0;
// Move data from shared memory into a local buffer. Do this // Move data from shared memory into a local buffer. Do this
// before parsing the blocks so that other processes can begin // before parsing the blocks so that other processes can begin
@ -111,11 +100,11 @@ std::vector<std::unique_ptr<BaseIpcMessage>> IpcDirectionalChannel::TakeMessages
get_free_message()->message_id = -1; get_free_message()->message_id = -1;
} }
std::vector<std::unique_ptr<BaseIpcMessage>> result; std::vector<std::unique_ptr<BaseIpcMessageElided>> result;
char* message = local_block; char* message = local_block;
while (remaining_bytes > 0) { while (remaining_bytes > 0) {
std::unique_ptr<BaseIpcMessage> base_message = IpcRegistry::instance()->Allocate(as_message(message)->message_id); std::unique_ptr<BaseIpcMessageElided> base_message = IpcRegistry::instance()->Allocate(as_message(message)->message_id);
rapidjson::Document document; rapidjson::Document document;
document.Parse(as_message(message)->payload(), as_message(message)->payload_size); document.Parse(as_message(message)->payload(), as_message(message)->payload_size);
@ -138,7 +127,7 @@ std::vector<std::unique_ptr<BaseIpcMessage>> IpcDirectionalChannel::TakeMessages
IpcServer::IpcServer(const std::string& name) IpcServer::IpcServer(const std::string& name)
: name_(name), server_(NameToServerName(name)) {} : name_(name), server_(NameToServerName(name)) {}
void IpcServer::SendToClient(int client_id, BaseIpcMessage* message) { void IpcServer::SendToClient(int client_id, BaseIpcMessageElided* message) {
// Find or create the client. // Find or create the client.
auto it = clients_.find(client_id); auto it = clients_.find(client_id);
if (it == clients_.end()) if (it == clients_.end())
@ -147,17 +136,17 @@ void IpcServer::SendToClient(int client_id, BaseIpcMessage* message) {
clients_[client_id]->PushMessage(message); clients_[client_id]->PushMessage(message);
} }
std::vector<std::unique_ptr<BaseIpcMessage>> IpcServer::TakeMessages() { std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcServer::TakeMessages() {
return server_.TakeMessages(); return server_.TakeMessages();
} }
IpcClient::IpcClient(const std::string& name, int client_id) IpcClient::IpcClient(const std::string& name, int client_id)
: server_(NameToServerName(name)), client_(NameToClientName(name, client_id)) {} : server_(NameToServerName(name)), client_(NameToClientName(name, client_id)) {}
void IpcClient::SendToServer(BaseIpcMessage* message) { void IpcClient::SendToServer(BaseIpcMessageElided* message) {
server_.PushMessage(message); server_.PushMessage(message);
} }
std::vector<std::unique_ptr<BaseIpcMessage>> IpcClient::TakeMessages() { std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcClient::TakeMessages() {
return client_.TakeMessages(); return client_.TakeMessages();
} }

70
ipc.h
View File

@ -31,9 +31,17 @@ struct JsonMessage {
using IpcMessageId = std::string; using IpcMessageId = std::string;
struct BaseIpcMessageElided {
virtual IpcMessageId runtime_id() const = 0;
virtual int hashed_runtime_id() const = 0;
virtual void Serialize(Writer& writer);
virtual void Deserialize(Reader& reader);
};
// Usage: // Usage:
// //
// class IpcMessage_Foo : public BaseIpcMessage { // class IpcMessage_Foo : public BaseIpcMessage<IpcMessage_Foo> {
// static IpcMessageId id; // static IpcMessageId id;
// //
// // BaseIpcMessage: // // BaseIpcMessage:
@ -45,23 +53,29 @@ using IpcMessageId = std::string;
// main() { // main() {
// IpcRegistry::instance()->Register<IpcMessage_Foo>(); // IpcRegistry::instance()->Register<IpcMessage_Foo>();
// } // }
struct BaseIpcMessage { //
// Note: This is a template so that the statics are stored separately
// per type.
template<typename T>
struct BaseIpcMessage : BaseIpcMessageElided {
BaseIpcMessage(); BaseIpcMessage();
virtual ~BaseIpcMessage(); virtual ~BaseIpcMessage();
virtual void Serialize(Writer& writer);
virtual void Deserialize(Reader& reader);
IpcMessageId runtime_id;
int hashed_runtime_id = -1;
// Populated by IpcRegistry::RegisterAllocator. // Populated by IpcRegistry::RegisterAllocator.
static IpcMessageId runtime_id_; static IpcMessageId runtime_id_;
static int hashed_runtime_id_; static int hashed_runtime_id_;
// BaseIpcMessageElided:
IpcMessageId runtime_id() const override {
return runtime_id_;
}
int hashed_runtime_id() const override {
return hashed_runtime_id_;
}
}; };
struct IpcRegistry { struct IpcRegistry {
using Allocator = std::function<BaseIpcMessage*()>; using Allocator = std::function<BaseIpcMessageElided*()>;
// Use unique_ptrs so we can initialize on first use // Use unique_ptrs so we can initialize on first use
// (static init order might not be right). // (static init order might not be right).
@ -71,7 +85,7 @@ struct IpcRegistry {
template<typename T> template<typename T>
void Register(); void Register();
std::unique_ptr<BaseIpcMessage> Allocate(int id); std::unique_ptr<BaseIpcMessageElided> Allocate(int id);
static IpcRegistry* instance() { static IpcRegistry* instance() {
if (!instance_) if (!instance_)
@ -115,8 +129,8 @@ struct IpcDirectionalChannel {
explicit IpcDirectionalChannel(const std::string& name); explicit IpcDirectionalChannel(const std::string& name);
~IpcDirectionalChannel(); ~IpcDirectionalChannel();
void PushMessage(BaseIpcMessage* message); void PushMessage(BaseIpcMessageElided* message);
std::vector<std::unique_ptr<BaseIpcMessage>> TakeMessages(); std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
private: private:
JsonMessage* get_free_message() { JsonMessage* get_free_message() {
@ -134,8 +148,8 @@ private:
struct IpcServer { struct IpcServer {
IpcServer(const std::string& name); IpcServer(const std::string& name);
void SendToClient(int client_id, BaseIpcMessage* message); void SendToClient(int client_id, BaseIpcMessageElided* message);
std::vector<std::unique_ptr<BaseIpcMessage>> TakeMessages(); std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
private: private:
std::string name_; std::string name_;
@ -146,10 +160,34 @@ private:
struct IpcClient { struct IpcClient {
IpcClient(const std::string& name, int client_id); IpcClient(const std::string& name, int client_id);
void SendToServer(BaseIpcMessage* message); void SendToServer(BaseIpcMessageElided* message);
std::vector<std::unique_ptr<BaseIpcMessage>> TakeMessages(); std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
private: private:
IpcDirectionalChannel server_; IpcDirectionalChannel server_;
IpcDirectionalChannel client_; IpcDirectionalChannel client_;
}; };
template<typename T>
BaseIpcMessage<T>::BaseIpcMessage() {
assert(!runtime_id_.empty() && "Message is not registered using IpcRegistry::RegisterAllocator");
}
template<typename T>
BaseIpcMessage<T>::~BaseIpcMessage() {}
template<typename T>
IpcMessageId BaseIpcMessage<T>::runtime_id_;
template<typename T>
int BaseIpcMessage<T>::hashed_runtime_id_ = -1;

1458
language_server_api.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
#if false
#include "platform.h" #include "platform.h"
#include <cassert> #include <cassert>
#include <string> #include <string>
#include <Windows.h> #include <Windows.h>
#include "utils.h"
struct PlatformMutexWin : public PlatformMutex { struct PlatformMutexWin : public PlatformMutex {
HANDLE raw_mutex = INVALID_HANDLE_VALUE; HANDLE raw_mutex = INVALID_HANDLE_VALUE;
@ -70,4 +71,3 @@ std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(PlatformM
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(const std::string& name) { std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(const std::string& name) {
return MakeUnique<PlatformSharedMemoryWin>(name); return MakeUnique<PlatformSharedMemoryWin>(name);
} }
#endif

View File

@ -166,6 +166,7 @@ struct SymbolIdx {
// TODO: Instead of passing to/from json, we can probably bass the IndexedFile type almost directly as // TODO: Instead of passing to/from json, we can probably bass the IndexedFile type almost directly as
// a raw memory dump - the type has almost zero pointers inside of it. We could do a little bit of fixup // a raw memory dump - the type has almost zero pointers inside of it. We could do a little bit of fixup
// so that passing from a separate process to the main db is really fast (no need to go through JSON). // so that passing from a separate process to the main db is really fast (no need to go through JSON).
/*
namespace foo2 { namespace foo2 {
using Usr = size_t; using Usr = size_t;
struct UsrTable { struct UsrTable {
@ -174,7 +175,7 @@ namespace foo2 {
const char* usrs[]; const char* usrs[];
}; };
} }
*/
struct IndexUpdate { struct IndexUpdate {
// File updates. // File updates.

View File

@ -230,7 +230,7 @@ void Deserialize(const Reader& reader, IndexedFile* file) {
std::string Serialize(IndexedFile* file) { std::string Serialize(IndexedFile* file) {
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output); Writer writer(output);
writer.SetFormatOptions( writer.SetFormatOptions(
rapidjson::PrettyFormatOptions::kFormatSingleLineArray); rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
writer.SetIndent(' ', 2); writer.SetIndent(' ', 2);