Clean Server (#93)
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "Async/Async.h"
|
||||
#include "Database.h"
|
||||
#include "Compiler/Module.h"
|
||||
#include "Compiler/Preamble.h"
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
struct CacheOption {
|
||||
/// The directory to store the cache files.
|
||||
std::string dir;
|
||||
};
|
||||
|
||||
/// This class is responsible for PCH and PCM building.
|
||||
class CacheController {
|
||||
public:
|
||||
CacheController(CacheOption& option, CompilationDatabase& database);
|
||||
|
||||
/// Generate `cache.json` to store the cache information.
|
||||
void loadFromDisk();
|
||||
|
||||
/// Load the cache information from `cache.json`.
|
||||
void saveToDisk();
|
||||
|
||||
/// Complete the PCH or PCM information required for the compilation arguments.
|
||||
/// If no suitable PCH or PCM is available, a build will be triggered.
|
||||
async::Task<> prepare(CompilationParams& params);
|
||||
|
||||
async::Task<> updatePCH();
|
||||
|
||||
private:
|
||||
const CacheOption& option;
|
||||
|
||||
CompilationDatabase& database;
|
||||
|
||||
struct CachedPCHInfo : PCHInfo {
|
||||
/// The hash of the preamble, for fast comparison.
|
||||
std::uint64_t hash;
|
||||
|
||||
/// The reference count of this PCH. When server exit, all PCH with zero
|
||||
/// reference count will be removed.
|
||||
std::uint32_t reference;
|
||||
};
|
||||
|
||||
/// All PCHs.
|
||||
std::deque<CachedPCHInfo> pchs;
|
||||
|
||||
/// A map between source file and its PCH.
|
||||
llvm::StringMap<CachedPCHInfo*> pchMap;
|
||||
|
||||
/// [module name] -> [PCMInfo]
|
||||
llvm::StringMap<PCMInfo> pcms;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@@ -8,7 +9,7 @@
|
||||
namespace clice::config {
|
||||
|
||||
/// Read the config file, call when the program starts.
|
||||
void load(llvm::StringRef execute, llvm::StringRef filename);
|
||||
std::expected<void, std::string> load(llvm::StringRef execute, llvm::StringRef filename);
|
||||
|
||||
/// Initialize the config, replace all predefined variables in the config file.
|
||||
/// called in `Server::initialize`.
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
/// `CompilationDatabase` is responsible for managing the compile commands.
|
||||
///
|
||||
/// FIXME: currently we assume that a file only occurs once in the CDB.
|
||||
/// This is not always correct, but it is enough for now.
|
||||
class CompilationDatabase {
|
||||
public:
|
||||
/// Update the compile commands with the given file.
|
||||
void updateCommands(llvm::StringRef file);
|
||||
|
||||
/// Update the compile commands with the given file and compile command.
|
||||
void updateCommand(llvm::StringRef file, llvm::StringRef command);
|
||||
|
||||
/// Update the module map with the given file and module name.
|
||||
void updateModule(llvm::StringRef file, llvm::StringRef name);
|
||||
|
||||
/// Lookup the compile commands of the given file.
|
||||
llvm::StringRef getCommand(llvm::StringRef file);
|
||||
|
||||
/// Lookup the module interface unit file path of the given module name.
|
||||
llvm::StringRef getModuleFile(llvm::StringRef name);
|
||||
|
||||
auto size() const {
|
||||
return commands.size();
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return commands.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return commands.end();
|
||||
}
|
||||
|
||||
private:
|
||||
/// A map between file path and compile commands.
|
||||
llvm::StringMap<std::string> commands;
|
||||
|
||||
/// For C++20 module, we only can got dependent module name
|
||||
/// in source context. But we need dependent module file path
|
||||
/// to build PCM. So we will scan(preprocess) all project files
|
||||
/// to build a module map between module name and module file path.
|
||||
/// **Note that** this only includes module interface unit, for module
|
||||
/// implementation unit, the scan could be delayed until compiling it.
|
||||
llvm::StringMap<std::string> moduleMap;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Database.h"
|
||||
#include "Protocol.h"
|
||||
#include "Async/Async.h"
|
||||
#include "Basic/SourceConverter.h"
|
||||
#include "Compiler/Command.h"
|
||||
#include "Compiler/Compilation.h"
|
||||
#include "Support/JSON.h"
|
||||
#include "Index/SymbolIndex.h"
|
||||
@@ -25,11 +25,12 @@ struct HeaderIndex {
|
||||
};
|
||||
|
||||
struct Context {
|
||||
/// The include chain that introduces this context.
|
||||
uint32_t include = -1;
|
||||
|
||||
/// The index information of this context.
|
||||
/// The index of header context in indices.
|
||||
uint32_t index = -1;
|
||||
|
||||
/// The location index in corresponding tu's
|
||||
/// all include locations.
|
||||
uint32_t include = -1;
|
||||
};
|
||||
|
||||
struct IncludeLocation {
|
||||
@@ -43,22 +44,10 @@ struct IncludeLocation {
|
||||
/// a header may be included by multiple files, so we use
|
||||
/// a string pool to cache the file name to reduce the memory
|
||||
/// usage.
|
||||
uint32_t filename = -1;
|
||||
uint32_t file = -1;
|
||||
};
|
||||
|
||||
struct Header {
|
||||
/// The path of the header file.
|
||||
std::string srcPath;
|
||||
|
||||
/// All indices of this header.
|
||||
std::vector<HeaderIndex> indices;
|
||||
|
||||
/// All header contexts of this header.
|
||||
llvm::DenseMap<TranslationUnit*, std::vector<Context>> contexts;
|
||||
|
||||
/// The active translation unit and the index of the context.
|
||||
std::pair<TranslationUnit*, uint32_t> active = {nullptr, -1};
|
||||
};
|
||||
struct Header;
|
||||
|
||||
struct TranslationUnit {
|
||||
/// The source file path.
|
||||
@@ -83,33 +72,46 @@ struct TranslationUnit {
|
||||
uint32_t version = 0;
|
||||
};
|
||||
|
||||
namespace proto {
|
||||
|
||||
struct IncludeLocation {
|
||||
/// The line number of the include directive.
|
||||
uint32_t line;
|
||||
|
||||
/// The filename of the included header.
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
struct HeaderContext {
|
||||
/// The path of the source file.
|
||||
std::string srcFile;
|
||||
TranslationUnit* tu = nullptr;
|
||||
|
||||
/// The path of the context file.
|
||||
std::string contextFile;
|
||||
Context context;
|
||||
|
||||
/// The index of the context.
|
||||
uint32_t index = -1;
|
||||
|
||||
/// The version of the context.
|
||||
uint32_t version = 0;
|
||||
bool valid() {
|
||||
return tu != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
using HeaderContextGroups = std::vector<std::vector<HeaderContext>>;
|
||||
struct Header {
|
||||
/// The path of the header file.
|
||||
std::string srcPath;
|
||||
|
||||
} // namespace proto
|
||||
/// The active header context.
|
||||
HeaderContext active;
|
||||
|
||||
/// All indices of the header.
|
||||
std::vector<HeaderIndex> indices;
|
||||
|
||||
/// All header contexts of this header.
|
||||
llvm::DenseMap<TranslationUnit*, std::vector<Context>> contexts;
|
||||
|
||||
/// Given a translation unit and a include location, return its
|
||||
/// its corresponding index.
|
||||
std::optional<uint32_t> getIndex(TranslationUnit* tu, uint32_t include) {
|
||||
auto it = contexts.find(tu);
|
||||
if(it == contexts.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for(auto& context: it->second) {
|
||||
if(context.include == include) {
|
||||
return context.index;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
class IncludeGraph {
|
||||
protected:
|
||||
@@ -123,62 +125,6 @@ protected:
|
||||
|
||||
async::Task<> index(llvm::StringRef file, CompilationDatabase& database);
|
||||
|
||||
public:
|
||||
/// Return all header context of the given file.
|
||||
/// FIXME: The results are grouped by the index file. And a header actually
|
||||
/// may have thousands of contexts, of course, users don't want to see all
|
||||
/// of them. For each index file, we return the first 10 contexts. In the future
|
||||
/// we may add a parameter to control the number of contexts or set filter.
|
||||
proto::HeaderContextGroups contextAll(llvm::StringRef file);
|
||||
|
||||
/// Return current header context of the given file.
|
||||
std::optional<proto::HeaderContext> contextCurrent(llvm::StringRef file);
|
||||
|
||||
/// Switch to the given header context.
|
||||
void contextSwitch(const proto::HeaderContext& context);
|
||||
|
||||
/// Resolve the header context to the include chain.
|
||||
std::vector<proto::IncludeLocation> contextResolve(const proto::HeaderContext& context);
|
||||
|
||||
private:
|
||||
struct SymbolID {
|
||||
uint64_t hash;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/// Return all indices of the given translation unit. If the file is empty,
|
||||
/// return all indices of the IncludeGraph.
|
||||
std::vector<std::string> indices(TranslationUnit* tu = nullptr);
|
||||
|
||||
/// Resolve the symbol at the given position.
|
||||
async::Task<std::vector<SymbolID>> resolve(const proto::TextDocumentPositionParams& params);
|
||||
|
||||
using LookupCallback = llvm::unique_function<bool(llvm::StringRef path,
|
||||
llvm::StringRef content,
|
||||
const index::SymbolIndex::Symbol& symbol)>;
|
||||
|
||||
async::Task<> lookup(llvm::ArrayRef<SymbolID> targets,
|
||||
llvm::ArrayRef<std::string> files,
|
||||
LookupCallback callback);
|
||||
|
||||
public:
|
||||
/// Lookup the reference information according to the given position.
|
||||
async::Task<proto::ReferenceResult> lookup(const proto::ReferenceParams& params,
|
||||
RelationKind kind);
|
||||
|
||||
/// According to the given file and offset, resolve the symbol at the offset.
|
||||
async::Task<proto::HierarchyPrepareResult>
|
||||
prepareHierarchy(const proto::HierarchyPrepareParams& params);
|
||||
|
||||
async::Task<proto::CallHierarchyIncomingCallsResult>
|
||||
incomingCalls(const proto::HierarchyParams& params);
|
||||
|
||||
async::Task<proto::CallHierarchyOutgoingCallsResult>
|
||||
outgoingCalls(const proto::HierarchyParams& params);
|
||||
|
||||
async::Task<proto::TypeHierarchyResult> typeHierarchy(const proto::HierarchyParams& params,
|
||||
bool super);
|
||||
|
||||
private:
|
||||
std::string getIndexPath(llvm::StringRef file);
|
||||
|
||||
@@ -190,7 +136,8 @@ private:
|
||||
uint32_t addIncludeChain(std::vector<IncludeLocation>& locations,
|
||||
llvm::DenseMap<clang::FileID, uint32_t>& files,
|
||||
clang::SourceManager& SM,
|
||||
clang::FileID fid);
|
||||
clang::FileID fid,
|
||||
ASTInfo& AST);
|
||||
|
||||
void addContexts(ASTInfo& info,
|
||||
TranslationUnit* tu,
|
||||
@@ -200,7 +147,7 @@ private:
|
||||
TranslationUnit* tu,
|
||||
llvm::DenseMap<clang::FileID, uint32_t>& files);
|
||||
|
||||
private:
|
||||
protected:
|
||||
const config::IndexOptions& options;
|
||||
llvm::StringMap<Header*> headers;
|
||||
llvm::StringMap<TranslationUnit*> tus;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Database.h"
|
||||
#include "Async/Async.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "IncludeGraph.h"
|
||||
#include "Async/Async.h"
|
||||
#include "Compiler/Command.h"
|
||||
#include "Index/FeatureIndex.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
class IncludeGraph;
|
||||
|
||||
class Indexer : public IncludeGraph {
|
||||
public:
|
||||
Indexer(CompilationDatabase& database, const config::IndexOptions& options);
|
||||
@@ -26,6 +25,78 @@ public:
|
||||
|
||||
void load();
|
||||
|
||||
public:
|
||||
Header* getHeader(llvm::StringRef file) const;
|
||||
|
||||
TranslationUnit* getTranslationUnit(llvm::StringRef file) const;
|
||||
|
||||
/// Return current header context of given header file. If the header
|
||||
/// does't have an active context, the result will be invalid.
|
||||
std::optional<proto::HeaderContext> currentContext(llvm::StringRef header) const;
|
||||
|
||||
/// Switch the context of the header to given context. If success,
|
||||
/// return true.
|
||||
bool switchContext(llvm::StringRef header, proto::HeaderContext context);
|
||||
|
||||
/// Resolve the given header context to a group of locations.
|
||||
std::vector<proto::IncludeLocation> resolveContext(proto::HeaderContext context) const;
|
||||
|
||||
/// Return all header contexts of given header file, note that a header may have thousands
|
||||
/// of header contexts, of course we won't return them all at once. We would return a group
|
||||
/// of contexts for each different header context. The maximum of group count is determined
|
||||
/// by limit. Optionally, you can specify a 'contextFile' to filter the results, returning only
|
||||
/// contexts related to that file.
|
||||
std::vector<proto::HeaderContextGroup>
|
||||
allContexts(llvm::StringRef headerFile,
|
||||
uint32_t limit = 10,
|
||||
llvm::StringRef contextFile = llvm::StringRef()) const;
|
||||
|
||||
public:
|
||||
struct SymbolID {
|
||||
uint64_t hash;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/// Return all indices of the given translation unit. If the file is empty,
|
||||
/// return all indices of the IncludeGraph.
|
||||
std::vector<std::string> indices(TranslationUnit* tu = nullptr);
|
||||
|
||||
/// Resolve the symbol at the given position.
|
||||
async::Task<std::vector<SymbolID>> resolve(const proto::TextDocumentPositionParams& params);
|
||||
|
||||
using LookupCallback = llvm::unique_function<bool(llvm::StringRef path,
|
||||
llvm::StringRef content,
|
||||
const index::SymbolIndex::Symbol& symbol)>;
|
||||
|
||||
async::Task<> lookup(llvm::ArrayRef<SymbolID> targets,
|
||||
llvm::ArrayRef<std::string> files,
|
||||
LookupCallback callback);
|
||||
|
||||
/// Lookup the reference information according to the given position.
|
||||
async::Task<proto::ReferenceResult> lookup(const proto::ReferenceParams& params,
|
||||
RelationKind kind);
|
||||
|
||||
/// According to the given file and offset, resolve the symbol at the offset.
|
||||
async::Task<proto::HierarchyPrepareResult>
|
||||
prepareHierarchy(const proto::HierarchyPrepareParams& params);
|
||||
|
||||
async::Task<proto::CallHierarchyIncomingCallsResult>
|
||||
incomingCalls(const proto::HierarchyParams& params);
|
||||
|
||||
async::Task<proto::CallHierarchyOutgoingCallsResult>
|
||||
outgoingCalls(const proto::HierarchyParams& params);
|
||||
|
||||
async::Task<proto::TypeHierarchyResult> typeHierarchy(const proto::HierarchyParams& params,
|
||||
bool super);
|
||||
|
||||
public:
|
||||
async::Task<std::optional<index::FeatureIndex>> getFeatureIndex(std::string& buffer,
|
||||
llvm::StringRef file) const;
|
||||
|
||||
async::Task<std::vector<feature::SemanticToken>> semanticTokens(llvm::StringRef file) const;
|
||||
|
||||
async::Task<std::vector<feature::FoldingRange>> foldingRanges(llvm::StringRef file) const;
|
||||
|
||||
private:
|
||||
async::Task<> index(std::string file);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Feature/FoldingRange.h"
|
||||
#include "Feature/DocumentSymbol.h"
|
||||
#include "Feature/SemanticTokens.h"
|
||||
#include "Server/Protocol.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
@@ -15,6 +16,26 @@ class LSPConverter {
|
||||
public:
|
||||
using Result = async::Task<json::Value>;
|
||||
|
||||
proto::InitializeResult initialize(json::Value value);
|
||||
|
||||
auto encoding() {
|
||||
return params.capabilities.general.positionEncodings[0];
|
||||
}
|
||||
|
||||
auto& capabilities() {
|
||||
return params.capabilities;
|
||||
}
|
||||
|
||||
/// The path of the workspace.
|
||||
llvm::StringRef workspace();
|
||||
|
||||
public:
|
||||
proto::SemanticTokens transform(llvm::StringRef content,
|
||||
llvm::ArrayRef<feature::SemanticToken> tokens);
|
||||
|
||||
std::vector<proto::FoldingRange> transform(llvm::StringRef content,
|
||||
llvm::ArrayRef<feature::FoldingRange> foldings);
|
||||
|
||||
Result convert(llvm::StringRef path, llvm::ArrayRef<feature::SemanticToken> tokens);
|
||||
|
||||
Result convert(llvm::StringRef path, llvm::ArrayRef<feature::FoldingRange> foldings);
|
||||
@@ -22,7 +43,8 @@ public:
|
||||
Result convert(const feature::Hover& hover);
|
||||
|
||||
private:
|
||||
proto::PositionEncodingKind kind;
|
||||
proto::InitializeParams params;
|
||||
std::string workspacePath;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -1,3 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "Basic/Lifecycle.h"
|
||||
#include "Basic/Lifecycle.h"
|
||||
|
||||
namespace clice::proto {
|
||||
|
||||
struct TextDocumentParams {
|
||||
/// The text document.
|
||||
TextDocumentIdentifier textDocument;
|
||||
};
|
||||
|
||||
enum class SemanticTokenTypes {
|
||||
Namespace,
|
||||
Type,
|
||||
Class,
|
||||
Enum,
|
||||
Interface,
|
||||
Struct,
|
||||
TypeParameter,
|
||||
Parameter,
|
||||
Variable,
|
||||
Property,
|
||||
EnumMember,
|
||||
Event,
|
||||
Function,
|
||||
Method,
|
||||
Macro,
|
||||
Keyword,
|
||||
Modifier,
|
||||
Comment,
|
||||
String,
|
||||
Number,
|
||||
Regexp,
|
||||
Operator,
|
||||
Decorator
|
||||
};
|
||||
|
||||
using SemanticTokensParams = TextDocumentParams;
|
||||
|
||||
using FoldingRangeParams = TextDocumentParams;
|
||||
|
||||
struct HeaderContext {
|
||||
/// The path of context file.
|
||||
std::string file;
|
||||
|
||||
/// The version of context file's AST.
|
||||
uint32_t version;
|
||||
|
||||
/// The include location id for further resolving.
|
||||
uint32_t include;
|
||||
};
|
||||
|
||||
struct IncludeLocation {
|
||||
/// The line of include drective.
|
||||
uint32_t line = -1;
|
||||
|
||||
/// The file path of include drective.
|
||||
std::string file;
|
||||
};
|
||||
|
||||
struct HeaderContextGroup {
|
||||
/// The index path of this header Context.
|
||||
std::string indexFile;
|
||||
|
||||
/// The header contexts.
|
||||
std::vector<HeaderContext> contexts;
|
||||
};
|
||||
|
||||
struct HeaderContextSwitchParams {
|
||||
/// The header file path which wants to switch context.
|
||||
std::string header;
|
||||
|
||||
/// The context
|
||||
HeaderContext context;
|
||||
};
|
||||
|
||||
} // namespace clice::proto
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cache.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
struct Rule {
|
||||
/// The file name pattern.
|
||||
std::string pattern;
|
||||
|
||||
/// ...
|
||||
std::vector<std::string> append;
|
||||
|
||||
/// ...
|
||||
std::vector<std::string> remove;
|
||||
|
||||
std::string readonly;
|
||||
|
||||
std::string header;
|
||||
|
||||
std::vector<std::string> context;
|
||||
};
|
||||
|
||||
/// This class is responsible for managing all opened files.
|
||||
class Scheduler {
|
||||
public:
|
||||
Scheduler(CompilationDatabase& database, llvm::ArrayRef<Rule> rules) :
|
||||
database(database), rules(rules) {}
|
||||
|
||||
async::Task<> open(llvm::StringRef path);
|
||||
|
||||
async::Task<> update(llvm::StringRef path);
|
||||
|
||||
async::Task<> close(llvm::StringRef path);
|
||||
|
||||
private:
|
||||
CompilationDatabase& database;
|
||||
|
||||
llvm::ArrayRef<Rule> rules;
|
||||
|
||||
struct File {};
|
||||
|
||||
llvm::StringMap<File> files;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
@@ -3,19 +3,92 @@
|
||||
#include "Config.h"
|
||||
#include "Indexer.h"
|
||||
#include "Protocol.h"
|
||||
#include "Database.h"
|
||||
#include "Scheduler.h"
|
||||
#include "LSPConverter.h"
|
||||
|
||||
#include "Async/Async.h"
|
||||
#include "Compiler/Command.h"
|
||||
|
||||
namespace clice {
|
||||
|
||||
namespace proto {
|
||||
|
||||
enum class ErrorCodes {
|
||||
// Defined by JSON-RPC
|
||||
ParseError = -32700,
|
||||
InvalidRequest = -32600,
|
||||
MethodNotFound = -32601,
|
||||
InvalidParams = -32602,
|
||||
InternalError = -32603,
|
||||
|
||||
/**
|
||||
* Error code indicating that a server received a notification or
|
||||
* request before the server has received the `initialize` request.
|
||||
*/
|
||||
ServerNotInitialized = -32002,
|
||||
UnknownErrorCode = -32001,
|
||||
|
||||
/**
|
||||
* A request failed but it was syntactically correct, e.g the
|
||||
* method name was known and the parameters were valid. The error
|
||||
* message should contain human readable information about why
|
||||
* the request failed.
|
||||
*
|
||||
* @since 3.17.0
|
||||
*/
|
||||
RequestFailed = -32803,
|
||||
|
||||
/**
|
||||
* The server cancelled the request. This error code should
|
||||
* only be used for requests that explicitly support being
|
||||
* server cancellable.
|
||||
*
|
||||
* @since 3.17.0
|
||||
*/
|
||||
ServerCancelled = -32802,
|
||||
|
||||
/**
|
||||
* The server detected that the content of a document got
|
||||
* modified outside normal conditions. A server should
|
||||
* NOT send this error code if it detects a content change
|
||||
* in it unprocessed messages. The result even computed
|
||||
* on an older state might still be useful for the client.
|
||||
*
|
||||
* If a client decides that a result is not of any use anymore
|
||||
* the client should cancel the request.
|
||||
*/
|
||||
ContentModified = -32801,
|
||||
|
||||
/**
|
||||
* The client has canceled a request and a server has detected
|
||||
* the cancel.
|
||||
*/
|
||||
RequestCancelled = -32800,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server();
|
||||
|
||||
async::Task<> onReceive(json::Value value);
|
||||
|
||||
/// Handle requests, a request must have a response.
|
||||
async::Task<json::Value> onRequest(llvm::StringRef method, json::Value value);
|
||||
|
||||
/// Handle requests started with `textDocument/`.
|
||||
async::Task<json::Value> onTextDocument(llvm::StringRef method, json::Value value);
|
||||
|
||||
/// Handle requests started with `context/`.
|
||||
async::Task<json::Value> onContext(llvm::StringRef method, json::Value value);
|
||||
|
||||
/// Handle requests started with `index/`.
|
||||
async::Task<json::Value> onIndex(llvm::StringRef method, json::Value value);
|
||||
|
||||
/// Handle notifications, a notification doesn't require response.
|
||||
async::Task<> onNotification(llvm::StringRef method, json::Value value);
|
||||
|
||||
private:
|
||||
/// Send a request to the client.
|
||||
async::Task<> request(llvm::StringRef method, json::Value params);
|
||||
|
||||
@@ -25,146 +98,21 @@ public:
|
||||
/// Send a response to the client.
|
||||
async::Task<> response(json::Value id, json::Value result);
|
||||
|
||||
async::Task<> response(json::Value id, proto::ErrorCodes code, llvm::StringRef message = "");
|
||||
|
||||
/// Send an register capability to the client.
|
||||
async::Task<> registerCapacity(llvm::StringRef id,
|
||||
llvm::StringRef method,
|
||||
json::Value registerOptions);
|
||||
|
||||
private:
|
||||
async::Task<> initialize(json::Value value);
|
||||
|
||||
public:
|
||||
std::uint32_t id = 0;
|
||||
|
||||
private:
|
||||
using onRequest = llvm::unique_function<async::Task<>(json::Value, json::Value)>;
|
||||
using onNotification = llvm::unique_function<async::Task<>(json::Value)>;
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name,
|
||||
async::Task<> (Server::*method)(json::Value, const Param&)) {
|
||||
requests.try_emplace(name,
|
||||
[this, method](json::Value id, json::Value value) -> async::Task<> {
|
||||
co_await (this->*method)(std::move(id),
|
||||
json::deserialize<Param>(value));
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name, async::Task<> (Server::*method)(const Param&)) {
|
||||
notifications.try_emplace(name, [this, method](json::Value value) -> async::Task<> {
|
||||
co_await (this->*method)(json::deserialize<Param>(value));
|
||||
});
|
||||
}
|
||||
|
||||
llvm::StringMap<onRequest> requests;
|
||||
llvm::StringMap<onNotification> notifications;
|
||||
|
||||
private:
|
||||
/// ============================================================================
|
||||
/// Lifecycle Message
|
||||
/// ============================================================================
|
||||
|
||||
async::Task<> onInitialize(json::Value id, const proto::InitializeParams& params);
|
||||
|
||||
async::Task<> onInitialized(const proto::InitializedParams& params);
|
||||
|
||||
async::Task<> onShutdown(json::Value id, const proto::None&);
|
||||
|
||||
async::Task<> onExit(const proto::None&);
|
||||
|
||||
/// ============================================================================
|
||||
/// Document Synchronization
|
||||
/// ============================================================================
|
||||
|
||||
async::Task<> onDidOpen(const proto::DidOpenTextDocumentParams& document);
|
||||
|
||||
async::Task<> onDidChange(const proto::DidChangeTextDocumentParams& document);
|
||||
|
||||
async::Task<> onDidSave(const proto::DidSaveTextDocumentParams& document);
|
||||
|
||||
async::Task<> onDidClose(const proto::DidCloseTextDocumentParams& document);
|
||||
|
||||
/// ============================================================================
|
||||
/// Language Features
|
||||
/// ============================================================================
|
||||
|
||||
// async::Task<> onGotoDeclaration(json::Value id, const proto::DeclarationParams& params);
|
||||
//
|
||||
// async::Task<> onGotoDefinition(json::Value id, const proto::DefinitionParams& params);
|
||||
//
|
||||
// async::Task<> onGotoTypeDefinition(json::Value id, const proto::TypeDefinitionParams&
|
||||
// params);
|
||||
//
|
||||
// async::Task<> onGotoImplementation(json::Value id, const proto::ImplementationParams&
|
||||
// params);
|
||||
//
|
||||
// async::Task<> onFindReferences(json::Value id, const proto::ReferenceParams& params);
|
||||
//
|
||||
// async::Task<> onPrepareCallHierarchy(json::Value id,
|
||||
// const proto::CallHierarchyPrepareParams& params);
|
||||
//
|
||||
// async::Task<> onIncomingCall(json::Value id,
|
||||
// const proto::CallHierarchyIncomingCallsParams& params);
|
||||
//
|
||||
// async::Task<> onOutgoingCall(json::Value id,
|
||||
// const proto::CallHierarchyOutgoingCallsParams& params);
|
||||
//
|
||||
// async::Task<> onPrepareTypeHierarchy(json::Value id,
|
||||
// const proto::TypeHierarchyPrepareParams& params);
|
||||
//
|
||||
// async::Task<> onSupertypes(json::Value id, const proto::TypeHierarchySupertypesParams&
|
||||
// params);
|
||||
//
|
||||
// async::Task<> onSubtypes(json::Value id, const proto::TypeHierarchySubtypesParams& params);
|
||||
|
||||
// async::Task<> onDocumentHighlight(json::Value id, const proto::DocumentHighlightParams&
|
||||
// params);
|
||||
//
|
||||
// async::Task<> onDocumentLink(json::Value id, const proto::DocumentLinkParams& params);
|
||||
//
|
||||
// async::Task<> onHover(json::Value id, const proto::HoverParams& params);
|
||||
//
|
||||
// async::Task<> onCodeLens(json::Value id, const proto::CodeLensParams& params);
|
||||
//
|
||||
// async::Task<> onFoldingRange(json::Value id, const proto::FoldingRangeParams& params);
|
||||
//
|
||||
// async::Task<> onDocumentSymbol(json::Value id, const proto::DocumentSymbolParams& params);
|
||||
//
|
||||
// async::Task<> onSemanticTokens(json::Value id, const proto::SemanticTokensParams& params);
|
||||
//
|
||||
// async::Task<> onInlayHint(json::Value id, const proto::InlayHintParams& params);
|
||||
//
|
||||
// async::Task<> onCodeCompletion(json::Value id, const proto::CompletionParams& params);
|
||||
//
|
||||
// async::Task<> onSignatureHelp(json::Value id, const proto::SignatureHelpParams& params);
|
||||
//
|
||||
// async::Task<> onCodeAction(json::Value id, const proto::CodeActionParams& params);
|
||||
//
|
||||
// async::Task<> onFormatting(json::Value id, const proto::DocumentFormattingParams& params);
|
||||
//
|
||||
// async::Task<> onRangeFormatting(json::Value id,
|
||||
// const proto::DocumentRangeFormattingParams& params);
|
||||
|
||||
/// ============================================================================
|
||||
/// Workspace Features
|
||||
/// ============================================================================
|
||||
|
||||
async::Task<> onDidChangeWatchedFiles(const proto::DidChangeWatchedFilesParams& params);
|
||||
|
||||
/// ============================================================================
|
||||
/// Extension
|
||||
/// ============================================================================
|
||||
|
||||
async::Task<> onIndexCurrent(const proto::TextDocumentIdentifier& params);
|
||||
|
||||
async::Task<> onIndexAll(const proto::None&);
|
||||
|
||||
async::Task<> onContextCurrent(const proto::TextDocumentIdentifier& params);
|
||||
|
||||
async::Task<> onContextAll(const proto::TextDocumentIdentifier& params);
|
||||
|
||||
async::Task<> onContextSwitch(const proto::TextDocumentIdentifier& params);
|
||||
|
||||
SourceConverter converter;
|
||||
CompilationDatabase database;
|
||||
Indexer indexer;
|
||||
Scheduler scheduler;
|
||||
LSPConverter converter;
|
||||
CompilationDatabase database;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
Reference in New Issue
Block a user