From 738762504a5f4e326aeab784f5681d5d8da0a388 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 9 Sep 2024 21:35:07 +0800 Subject: [PATCH] some update. --- .vscode/launch.json | 7 +- CMakeLists.txt | 2 +- include/Protocol/Lifecycle/Initialize.h | 25 + include/Protocol/Lifecycle/Initialized.h | 7 + include/Protocol/Protocol.h | 709 +---------------------- include/Protocol/Protocol2.h | 709 +++++++++++++++++++++++ include/Server/Scheduler .h | 2 + include/Server/Server.h | 32 +- include/Support/Reflection.h | 4 +- src/Server/Server.cpp | 92 ++- src/main.cpp | 4 +- 11 files changed, 839 insertions(+), 754 deletions(-) create mode 100644 include/Protocol/Protocol2.h diff --git a/.vscode/launch.json b/.vscode/launch.json index 56e55913..c98acd13 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,10 +6,9 @@ "configurations": [ { "type": "lldb", - "request": "launch", - "name": "ASTVisitor", - "program": "${workspaceFolder}/build/bin/clice", - "cwd": "${workspaceFolder}" + "request": "attach", + "name": "clice", + "program": "clice" }, { "type": "lldb", diff --git a/CMakeLists.txt b/CMakeLists.txt index 81624024..ec0a07fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(CLICE) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -w -fno-rtti -O0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -w -fno-rtti -g -O0") set(LLVM_INSTALL_PATH "${CMAKE_SOURCE_DIR}/deps/llvm/build-install") diff --git a/include/Protocol/Lifecycle/Initialize.h b/include/Protocol/Lifecycle/Initialize.h index 3a1d81a7..0c03b2a4 100644 --- a/include/Protocol/Lifecycle/Initialize.h +++ b/include/Protocol/Lifecycle/Initialize.h @@ -8,6 +8,31 @@ enum class TextDocumentSyncKind { Incremental = 2, }; +struct ClientInfo { + /// The name of the client as defined by the client. + string name; + /// The client's version as defined by the client. + string version; +}; + +struct ClientCapabilities {}; + +struct InitializeParams { + /// Information about the client + ClientInfo clientInfo; + + /// The locale the client is currently showing the user interface + /// in. This must not necessarily be the locale of the operating + /// system. + /// + /// Uses IETF language tags as the value's syntax. + /// (See https://en.wikipedia.org/wiki/IETF_language_tag) + string locale; + + /// The capabilities provided by the client (editor or tool). + ClientCapabilities capabilities; +}; + struct ServerCapabilities { std::string_view positionEncoding = "utf-16"; TextDocumentSyncKind textDocumentSync = TextDocumentSyncKind::Full; diff --git a/include/Protocol/Lifecycle/Initialized.h b/include/Protocol/Lifecycle/Initialized.h index e69de29b..df108f29 100644 --- a/include/Protocol/Lifecycle/Initialized.h +++ b/include/Protocol/Lifecycle/Initialized.h @@ -0,0 +1,7 @@ +#pragma once + +namespace clice::protocol { + +struct InitializedParams {}; + +} // namespace clice::protocol diff --git a/include/Protocol/Protocol.h b/include/Protocol/Protocol.h index 4eae7d5a..99d64069 100644 --- a/include/Protocol/Protocol.h +++ b/include/Protocol/Protocol.h @@ -1,709 +1,4 @@ #pragma once -#include -#include -#include -#include - -#include "Language/SemanticToken.h" - -namespace clice { - -// Defined by JSON RPC. -enum class ErrorCode { - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - - // Defined by the protocol. - RequestCancelled = -32800, - ContentModified = -32801, -}; - -struct ResourceOperationKind { - /// Supports creating new files and folders. - constexpr inline static std::string_view Create = "create"; - - /// Supports renaming existing files and folders. - constexpr inline static std::string_view Rename = "rename"; - - /// Supports deleting existing files and folders. - constexpr inline static std::string_view Delete = "delete"; -}; - -struct FailureHandlingKind { - /// Applying the workspace change is simply aborted if one of the changes - /// provided fails. All operations executed before the failing operation stay - /// executed. - constexpr inline static std::string_view Abort = "abort"; - - /// All operations are executed transactionally. That is they either all - /// succeed or no changes at all are applied to the workspace. - constexpr inline static std::string_view Transactional = "transactional"; - - /// If the workspace edit contains only textual file changes they are executed - /// transactionally. If resource changes (create, rename or delete file) are - /// part of the change the failure handling strategy is abort. - constexpr inline static std::string_view TextOnlyTransactional = "textOnlyTransactional"; - - /// The client tries to undo the operations already executed. But there is no - /// guarantee that this is succeeding. - constexpr inline static std::string_view Undo = "undo"; -}; - -/// A symbol kind. -enum class SymbolKind { - 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, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26, -}; - -struct WorkspaceEditClientCapabilities { - /// The client supports versioned document changes in `WorkspaceEdit`s - std::optional documentChanges; - - /// The resource operations the client supports. Clients should at least - /// support 'create', 'rename' and 'delete' files and folders. - /// possible values are in ResourceOperationKind - std::optional> resourceOperations; - - /// The failure handling strategy of a client if applying the workspace edit - /// fails. - /// possible values are in FailureHandlingKind - std::optional failureHandling; - - /// Whether the client normalizes line endings to the client specific - /// setting. - /// If set to `true` the client will normalize line ending characters - /// in a workspace edit to the client specific new line character(s). - std::optional normalizesLineEndings; - - struct ChangeAnnotationSupport { - /// Whether the client groups edits with equal labels into tree nodes, - /// for instance all edits labelled with "Changes in Strings" would - /// be a tree node. - std::optional groupsOnLabel; - }; - - /// Whether the client in general supports change annotations on text edits, - /// create file, rename file and delete file changes. - std::optional changeAnnotationSupport; -}; - -struct DidChangeConfigurationClientCapabilities { - /// Did change configuration notification supports dynamic registration. - std::optional dynamicRegistration; -}; - -struct DidChangeWatchedFilesClientCapabilities { - /// Did change watched files notification supports dynamic registration. - /// Please note that the current protocol doesn't support static - /// configuration for file changes from the server side. - std::optional dynamicRegistration; - - /// Whether the client has support for relative patterns or not. - std::optional supportsRelativePattern; -}; - -struct WorkspaceSymbolClientCapabilities { - /// Symbol request supports dynamic registration. - std::optional dynamicRegistration; - - struct SymbolKind_ { - /// The symbol kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - /// - /// If this property is not present the client only supports - /// the symbol kinds from `File` to `Array` as defined in - /// the initial version of the protocol. - std::vector valueSet; - }; - - /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. - std::optional symbolKind; - - struct TagSupport { - /// The tags supported by the client. - std::vector valueSet; - }; - - /// The client supports tags on `SymbolInformation` and `WorkspaceSymbol`. - /// Clients supporting tags have to handle unknown tags gracefully. - std::optional tagSupport; - - struct ResolveSupport { - /// The properties that a client can resolve lazily. Usually `location.range`. - std::vector properties; - }; - - /// The client support partial workspace symbols. The client will send the - /// request `workspaceSymbol/resolve` to the server to resolve additional - /// properties. - std::optional resolveSupport; -}; - -struct ExecuteCommandClientCapabilities { - /// Execute command supports dynamic registration. - std::optional dynamicRegistration; -}; - -struct SemanticTokensWorkspaceClientCapabilities { - /// Whether the client implementation supports a refresh request sent from - /// the server to the client. - /// - /// Note that this event is global and will force the client to refresh all - /// semantic tokens currently shown. It should be used with absolute care - /// and is useful for situation where a server for example detect a project - /// wide change that requires such a calculation. - std::optional refreshSupport; -}; - -struct CodeLensWorkspaceClientCapabilities { - /** - * Whether the client implementation supports a refresh request sent from the - * server to the client. - * - * Note that this event is global and will force the client to refresh all - * code lenses currently shown. It should be used with absolute care and is - * useful for situation where a server for example detect a project wide - * change that requires such a calculation. - */ - std::optional refreshSupport; -}; - -/// Client workspace capabilities specific to inline values. -struct InlineValueWorkspaceClientCapabilities { - /// Whether the client implementation supports a refresh request sent from - /// the server to the client. - /// - /// Note that this event is global and will force the client to refresh all - /// inline values currently shown. It should be used with absolute care and - /// is useful for situation where a server for example detect a project wide - /// change that requires such a calculation. - std::optional refreshSupport; -}; - -/// Client workspace capabilities specific to inlay hints. -struct InlayHintWorkspaceClientCapabilities { - /// Whether the client implementation supports a refresh request sent from - /// the server to the client. - /// - /// Note that this event is global and will force the client to refresh all - /// inlay hints currently shown. It should be used with absolute care and - /// is useful for situation where a server for example detects a project wide - /// change that requires such a calculation. - std::optional refreshSupport; -}; - -/// Workspace client capabilities specific to diagnostic pull requests. -struct DiagnosticWorkspaceClientCapabilities { - /// Whether the client implementation supports a refresh request sent from - /// the server to the client. - /// - /// Note that this event is global and will force the client to refresh all - /// pulled diagnostics currently shown. It should be used with absolute care - /// and is useful for situation where a server for example detects a project - /// wide change that requires such a calculation. - std::optional refreshSupport; -}; - -struct ClientCapabilities { - struct Workplace { - /// The client supports applying batch edits - /// to the workspace by supporting the request - /// 'workspace/applyEdit' - std::optional applyEdit; - - /// Capabilities specific to `WorkspaceEdit`s - std::optional workspaceEdit; - - /// Capabilities specific to the `workspace/didChangeConfiguration` notification. - std::optional didChangeConfiguration; - - /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - std::optional didChangeWatchedFiles; - - /// Capabilities specific to the `workspace/symbol` request. - std::optional symbol; - - /// Capabilities specific to the `workspace/executeCommand` request. - std::optional executeCommand; - - /// The client has support for workspace folders. - std::optional workspaceFolders; - - /// The client supports `workspace/configuration` requests. - std::optional configuration; - - /// Capabilities specific to the semantic token requests scoped to the workspace. - std::optional semanticTokens; - - /// Capabilities specific to the code lens requests scoped to the workspace. - std::optional codeLens; - - struct FileOperations { - /// Whether the client supports dynamic registration for file requests/notifications. - std::optional dynamicRegistration; - - /// The client has support for sending didCreateFiles notifications. - std::optional didCreate; - - /// The client has support for sending willCreateFiles requests. - std::optional willCreate; - - /// The client has support for sending didRenameFiles notifications. - std::optional didRename; - - /// The client has support for sending willRenameFiles requests. - std::optional willRename; - - /// The client has support for sending didDeleteFiles notifications. - std::optional didDelete; - - /// The client has support for sending willDeleteFiles requests. - std::optional willDelete; - }; - - /// The client has support for file requests/notifications. - std::optional fileOperations; - - /// Client workspace capabilities specific to inline values. - std::optional inlineValue; - - /// Client workspace capabilities specific to inlay hints. - std::optional inlayHint; - - /// Client workspace capabilities specific to diagnostics. - std::optional diagnostic; - }; - - /// Workspace specific client capabilities. - std::optional workspace; - - /// Text document specific client capabilities. - /// TODO: textDocument?: TextDocumentClientCapabilities; - - /// Capabilities specific to the notebook document support. - /// TODO: notebookDocument?: NotebookDocumentClientCapabilities; - - /// Window specific client capabilities. - /// TODO: window: {...} - - /// General client capabilities. - /// TODO: general: {...} - - /// Experimental client capabilities. - /// experimental?: LSPAny; -}; - -/// TODO: -struct URI {}; - -struct WorkspaceFolder { - /// The associated URI for this workspace folder. - URI uri; - - /// The name of the workspace folder. Used to refer to this - /// workspace folder in the user interface. - std::string name; -}; - -struct InitializeParams { - /// The process Id of the parent process that started the server. Is null if - /// the process has not been started by another process. If the parent - /// process is not alive then the server should exit (see exit notification) - /// its process. - std::optional processId; - - struct ClientInfo { - std::string_view name; - std::optional version; - }; - - /// Information about the client - std::optional clientInfo; - - /// The locale the client is currently showing the user interface - /// in. This must not necessarily be the locale of the operating - /// system. - /// - /// Uses IETF language tags as the value's syntax - /// (See https://en.wikipedia.org/wiki/IETF_language_tag) - /// - /// @since 3.16.0 - std::optional locale; - - /// User provided initialization options. - /// TODO: initializationOptions?: LSPAny; - - /// The capabilities provided by the client (editor or tool). - ClientCapabilities capabilities; - - /// The initial trace setting. If omitted trace is disabled ('off'). - /// TODO: trace?: TraceValue; - - /// The workspace folders configured in the client when the server starts. - /// This property is only available if the client supports workspace folders. - /// It can be `null` if the client supports workspace folders but none are - /// configured. - std::optional> workspaceFolders; -}; - -/*===========================================================================// -// RESPONSES // -//===========================================================================*/ - -struct PositionEncodingKind { - /// Character offsets count UTF-8 code units (e.g bytes). - constexpr inline static std::string_view UTF8 = "utf-8"; - - /// Character offsets count UTF-16 code units. - /// This is the default and must always be supported by servers. - constexpr inline static std::string_view UTF16 = "utf-16"; - - /// Character offsets count UTF-32 code units. - /// Implementation note: these are the same as Unicode code points, - /// so this `PositionEncodingKind` may also be used for an - /// encoding-agnostic representation of character offsets. - constexpr inline static std::string_view UTF32 = "utf-32"; -}; - -/// Defines how the host (editor) should sync document changes to the language server. -enum class TextDocumentSyncKind { - /// Documents should not be synced at all. - None = 0, - - /// Documents are synced by always sending the full content of the document. - Full = 1, - - /// Documents are synced by sending the full content on open. After that only - /// incremental updates to the document are sent. - Incremental = 2, -}; - -/// Completion options. -struct CompletionOptions { - /// - /// The additional characters, beyond the defaults provided by the client (typically - ///[a-zA-Z]), that should automatically trigger a completion request. For example - ///`.` in JavaScript represents the beginning of an object property or method and is - /// thus a good candidate for triggering a completion request. - /// - /// Most tools trigger a completion request automatically without explicitly - /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they - /// do so when the user starts to type an identifier. For example if the user - /// types `c` in a JavaScript file code complete will automatically pop up - /// present `console` besides others as a completion item. Characters that - /// make up identifiers don't need to be listed here. - std::array triggerCharacters = {".", "<", ">", ":", "\"", "/", "*"}; - - /// The list of all possible characters that commit a completion. This field - /// can be used if clients don't support individual commit characters per - /// completion item. See client capability `completion.completionItem.commitCharactersSupport`. - /// - /// If a server provides both `allCommitCharacters` and commit characters on - /// an individual completion item the ones on the completion item win. - /// - /// allCommitCharacters?: string[]; - /// NOTICE: We don't set `(` etc as allCommitCharacters as they interact poorly with snippet results. - /// See https://github.com/clangd/vscode-clangd/issues/357 - /// Hopefully we can use them one day without this side-effect: - /// https://github.com/microsoft/vscode/issues/42544 - - /// The server provides support to resolve additional information for a completion item. - bool resolveProvider = false; - - /// The server supports the following `CompletionItem` specific capabilities. - /// TODO: completionItem?: {...} -}; - -struct SignatureHelpOptions { - /// The characters that trigger signature help automatically. - std::array triggerCharacters = {"(", ")", "{", "}", "<", ">", ","}; - - /// List of characters that re-trigger signature help. - /// These trigger characters are only active when signature help is already showing. - /// All trigger characters are also counted as re-trigger characters. - std::array retriggerCharacters = {","}; -}; - -struct CodeLensOptions { - /// Code lens has a resolve provider as well. - bool resolveProvider = false; -}; - -struct DocumentLinkOptions { - /// Document links have a resolve provider as well. - bool resolveProvider = false; -}; - -struct DocumentOnTypeFormattingOptions { - /// A character on which formatting should be triggered, like `{`. - std::string_view firstTriggerCharacter = "\n"; - - /// More trigger characters. - /// moreTriggerCharacter?: string[]; -}; - -struct SemanticTokensOptions { - /// The legend used by the server - protocol::SemanticTokensLegend legend; - - /// Server supports providing semantic tokens for a specific range of a document. - bool range = false; // TODO: further check - - struct Full { - /// Server supports providing semantic tokens for a full document. - bool delta = true; - }; - - /// Server supports providing semantic tokens for a full document. - Full full; -}; - -struct ServerCapabilities { - /// The position encoding the server picked from the encodings offered - /// by the client via the client capability `general.positionEncodings`. - /// - /// If the client didn't provide any position encodings the only valid - /// value that a server can return is 'utf-16'. - /// - /// If omitted it defaults to 'utf-16'. - /// - /// possible values: ['utf-8', 'utf-16', 'utf-32'] in PositionEncodingKind - std::string_view positionEncoding = PositionEncodingKind::UTF16; - - /// Defines how text documents are synced. Is either a detailed structure - /// defining each notification or for backwards compatibility the - /// TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`. - TextDocumentSyncKind textDocumentSync = TextDocumentSyncKind::Incremental; - - /// Defines how notebook documents are synced. - /// TODO: notebookDocumentSync?: NotebookDocumentSyncOptions | NotebookDocumentSyncRegistrationOptions; - - /// The server provides completion support. - CompletionOptions completionProvider; - - /// The server provides hover support. - bool hoverProvider = true; - - /// The server provides signature help support. - SignatureHelpOptions signatureHelpProvider; - - /// The server provides go to declaration support. - bool declarationProvider = true; - - /// The server provides goto definition support. - bool definitionProvider = true; - - /// The server provides goto type definition support. - bool typeDefinitionProvider = true; - - /// The server provides goto implementation support. - bool implementationProvider = true; - - /// The server provides find references support. - bool referencesProvider = true; - - /// The server provides document highlight support. - bool documentHighlightProvider = true; - - /// The server provides document symbol support. - bool documentSymbolProvider = true; - - /// The server provides code actions. The `CodeActionOptions` return type is - /// only valid if the client signals code action literal support via the - /// client capability `textDocument.codeAction.codeActionLiteralSupport`. - bool codeActionProvider = true; // TODO: provide CodeActionOptions - - /// The server provides code lens. - CodeLensOptions codeLensProvider; - - /// The server provides document link support. - DocumentLinkOptions documentLinkProvider; - - /// The server provides color provider support. - bool colorProvider = false; // TODO: check what is colorProvider - - /// The server provides document formatting. - bool documentFormattingProvider = true; - - /// The server provides document range formatting. - bool documentRangeFormattingProvider = true; - - /// The server provides document formatting on typing. - DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; - - /// The server provides rename support. RenameOptions may only be - /// specified if the client states that it supports - /// `prepareSupport` in its initial `initialize` request. - bool renameProvider = true; - - /// The server provides folding provider support. - bool foldingRangeProvider = true; - - /// The server provides execute command support. - /// executeCommandProvider?: ExecuteCommandOptions; - - /// The server provides selection range support. - bool selectionRangeProvider = true; - - /// The server provides linked editing range support. - bool linkedEditingRangeProvider = true; - - /// The server provides call hierarchy support. - bool callHierarchyProvider = true; - - /// The server provides semantic tokens support. - SemanticTokensOptions semanticTokensProvider; - - /// Whether server provides moniker support. - bool monikerProvider = false; // TODO: further discussion - - /// The server provides type hierarchy support. - bool typeHierarchyProvider = true; - - /// The server provides inline values. - bool inlineValueProvider = true; - - /// The server provides inlay hints. - bool inlayHintProvider = true; - - /// The server has support for pull model diagnostics. - /// TODO: diagnosticProvider?: DiagnosticOptions - - /// The server provides workspace symbol support. - bool workspaceSymbolProvider = true; - - /// The server is interested in file notifications/requests. - /// TODO: fileOperations?: {...} -}; - -struct InitializeResult { - /// The capabilities the language server provides. - ServerCapabilities capabilities; - - struct ServerInfo { - /// The name of the server as defined by the server. - std::string_view name = "clice"; - - /// The server's version as defined by the server. - std::string_view version = "0.0.1"; - }; - - /// Information about the server. - ServerInfo serverInfo; -}; - -/*===================================================/ -/ / -/======= Text Document Synchronization ==========/ -/ / -/===================================================*/ - -/// An item to transfer a text document from the client to the server. -struct TextDocumentItem { - /// The text document's URI. - std::string_view uri; - - /// The text document's language identifier. - std::string_view languageId; - - /// he version number of this document (it will increase after each change, including undo/redo). - int version; - - /// The content of the opened text document. - std::string_view text; -}; - -/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. -struct TextDocumentIdentifier { - /// The text document's URI. - std::string_view uri; -}; - -struct VersionedTextDocumentIdentifier { - /// The text document's URI. - std::string_view uri; - - /// The version number of this document. - /// - /// The version number of a document will increase after each change, - /// including undo/redo. The number doesn't need to be consecutive. - int version; -}; - -struct DidOpenTextDocumentParams { - /// The document that was opened. - TextDocumentItem textDocument; -}; - -struct TextDocumentContentChangeEvent { - // TODO: -}; - -struct DidChangeTextDocumentParams { - /// The document that did change. The version number points - /// to the version after all provided content changes have - /// been applied. - VersionedTextDocumentIdentifier textDocument; - - /// The actual content changes. The content changes describe single state - /// changes to the document. So if there are two content changes c1 (at - /// array index 0) and c2 (at array index 1) for a document in state S then - /// c1 moves the document from S to S' and c2 from S' to S''. So c1 is - /// computed on the state S and c2 is computed on the state S'. - /// - /// To mirror the content of a document using change events use the following - /// approach: - /// - start with the same initial content - /// - apply the 'textDocument/didChange' notifications in the order you receive them. - /// - apply the `TextDocumentContentChangeEvent`s in a single notification in the order you receive them. - std::vector contentChanges; -}; - -struct DidCloseTextDocumentParams { - /// The document that was closed. - TextDocumentIdentifier textDocument; -}; - -struct DidSaveTextDocumentParams { - /// The document that was saved. - TextDocumentIdentifier textDocument; - - /// Optional the content when saved. Depends on the includeText value - /// when the save notification was requested. - std::optional text; -}; - -} // namespace clice +#include +#include diff --git a/include/Protocol/Protocol2.h b/include/Protocol/Protocol2.h new file mode 100644 index 00000000..4eae7d5a --- /dev/null +++ b/include/Protocol/Protocol2.h @@ -0,0 +1,709 @@ +#pragma once + +#include +#include +#include +#include + +#include "Language/SemanticToken.h" + +namespace clice { + +// Defined by JSON RPC. +enum class ErrorCode { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, + + // Defined by the protocol. + RequestCancelled = -32800, + ContentModified = -32801, +}; + +struct ResourceOperationKind { + /// Supports creating new files and folders. + constexpr inline static std::string_view Create = "create"; + + /// Supports renaming existing files and folders. + constexpr inline static std::string_view Rename = "rename"; + + /// Supports deleting existing files and folders. + constexpr inline static std::string_view Delete = "delete"; +}; + +struct FailureHandlingKind { + /// Applying the workspace change is simply aborted if one of the changes + /// provided fails. All operations executed before the failing operation stay + /// executed. + constexpr inline static std::string_view Abort = "abort"; + + /// All operations are executed transactionally. That is they either all + /// succeed or no changes at all are applied to the workspace. + constexpr inline static std::string_view Transactional = "transactional"; + + /// If the workspace edit contains only textual file changes they are executed + /// transactionally. If resource changes (create, rename or delete file) are + /// part of the change the failure handling strategy is abort. + constexpr inline static std::string_view TextOnlyTransactional = "textOnlyTransactional"; + + /// The client tries to undo the operations already executed. But there is no + /// guarantee that this is succeeding. + constexpr inline static std::string_view Undo = "undo"; +}; + +/// A symbol kind. +enum class SymbolKind { + 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, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + TypeParameter = 26, +}; + +struct WorkspaceEditClientCapabilities { + /// The client supports versioned document changes in `WorkspaceEdit`s + std::optional documentChanges; + + /// The resource operations the client supports. Clients should at least + /// support 'create', 'rename' and 'delete' files and folders. + /// possible values are in ResourceOperationKind + std::optional> resourceOperations; + + /// The failure handling strategy of a client if applying the workspace edit + /// fails. + /// possible values are in FailureHandlingKind + std::optional failureHandling; + + /// Whether the client normalizes line endings to the client specific + /// setting. + /// If set to `true` the client will normalize line ending characters + /// in a workspace edit to the client specific new line character(s). + std::optional normalizesLineEndings; + + struct ChangeAnnotationSupport { + /// Whether the client groups edits with equal labels into tree nodes, + /// for instance all edits labelled with "Changes in Strings" would + /// be a tree node. + std::optional groupsOnLabel; + }; + + /// Whether the client in general supports change annotations on text edits, + /// create file, rename file and delete file changes. + std::optional changeAnnotationSupport; +}; + +struct DidChangeConfigurationClientCapabilities { + /// Did change configuration notification supports dynamic registration. + std::optional dynamicRegistration; +}; + +struct DidChangeWatchedFilesClientCapabilities { + /// Did change watched files notification supports dynamic registration. + /// Please note that the current protocol doesn't support static + /// configuration for file changes from the server side. + std::optional dynamicRegistration; + + /// Whether the client has support for relative patterns or not. + std::optional supportsRelativePattern; +}; + +struct WorkspaceSymbolClientCapabilities { + /// Symbol request supports dynamic registration. + std::optional dynamicRegistration; + + struct SymbolKind_ { + /// The symbol kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the symbol kinds from `File` to `Array` as defined in + /// the initial version of the protocol. + std::vector valueSet; + }; + + /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + std::optional symbolKind; + + struct TagSupport { + /// The tags supported by the client. + std::vector valueSet; + }; + + /// The client supports tags on `SymbolInformation` and `WorkspaceSymbol`. + /// Clients supporting tags have to handle unknown tags gracefully. + std::optional tagSupport; + + struct ResolveSupport { + /// The properties that a client can resolve lazily. Usually `location.range`. + std::vector properties; + }; + + /// The client support partial workspace symbols. The client will send the + /// request `workspaceSymbol/resolve` to the server to resolve additional + /// properties. + std::optional resolveSupport; +}; + +struct ExecuteCommandClientCapabilities { + /// Execute command supports dynamic registration. + std::optional dynamicRegistration; +}; + +struct SemanticTokensWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// semantic tokens currently shown. It should be used with absolute care + /// and is useful for situation where a server for example detect a project + /// wide change that requires such a calculation. + std::optional refreshSupport; +}; + +struct CodeLensWorkspaceClientCapabilities { + /** + * Whether the client implementation supports a refresh request sent from the + * server to the client. + * + * Note that this event is global and will force the client to refresh all + * code lenses currently shown. It should be used with absolute care and is + * useful for situation where a server for example detect a project wide + * change that requires such a calculation. + */ + std::optional refreshSupport; +}; + +/// Client workspace capabilities specific to inline values. +struct InlineValueWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// inline values currently shown. It should be used with absolute care and + /// is useful for situation where a server for example detect a project wide + /// change that requires such a calculation. + std::optional refreshSupport; +}; + +/// Client workspace capabilities specific to inlay hints. +struct InlayHintWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// inlay hints currently shown. It should be used with absolute care and + /// is useful for situation where a server for example detects a project wide + /// change that requires such a calculation. + std::optional refreshSupport; +}; + +/// Workspace client capabilities specific to diagnostic pull requests. +struct DiagnosticWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// pulled diagnostics currently shown. It should be used with absolute care + /// and is useful for situation where a server for example detects a project + /// wide change that requires such a calculation. + std::optional refreshSupport; +}; + +struct ClientCapabilities { + struct Workplace { + /// The client supports applying batch edits + /// to the workspace by supporting the request + /// 'workspace/applyEdit' + std::optional applyEdit; + + /// Capabilities specific to `WorkspaceEdit`s + std::optional workspaceEdit; + + /// Capabilities specific to the `workspace/didChangeConfiguration` notification. + std::optional didChangeConfiguration; + + /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + std::optional didChangeWatchedFiles; + + /// Capabilities specific to the `workspace/symbol` request. + std::optional symbol; + + /// Capabilities specific to the `workspace/executeCommand` request. + std::optional executeCommand; + + /// The client has support for workspace folders. + std::optional workspaceFolders; + + /// The client supports `workspace/configuration` requests. + std::optional configuration; + + /// Capabilities specific to the semantic token requests scoped to the workspace. + std::optional semanticTokens; + + /// Capabilities specific to the code lens requests scoped to the workspace. + std::optional codeLens; + + struct FileOperations { + /// Whether the client supports dynamic registration for file requests/notifications. + std::optional dynamicRegistration; + + /// The client has support for sending didCreateFiles notifications. + std::optional didCreate; + + /// The client has support for sending willCreateFiles requests. + std::optional willCreate; + + /// The client has support for sending didRenameFiles notifications. + std::optional didRename; + + /// The client has support for sending willRenameFiles requests. + std::optional willRename; + + /// The client has support for sending didDeleteFiles notifications. + std::optional didDelete; + + /// The client has support for sending willDeleteFiles requests. + std::optional willDelete; + }; + + /// The client has support for file requests/notifications. + std::optional fileOperations; + + /// Client workspace capabilities specific to inline values. + std::optional inlineValue; + + /// Client workspace capabilities specific to inlay hints. + std::optional inlayHint; + + /// Client workspace capabilities specific to diagnostics. + std::optional diagnostic; + }; + + /// Workspace specific client capabilities. + std::optional workspace; + + /// Text document specific client capabilities. + /// TODO: textDocument?: TextDocumentClientCapabilities; + + /// Capabilities specific to the notebook document support. + /// TODO: notebookDocument?: NotebookDocumentClientCapabilities; + + /// Window specific client capabilities. + /// TODO: window: {...} + + /// General client capabilities. + /// TODO: general: {...} + + /// Experimental client capabilities. + /// experimental?: LSPAny; +}; + +/// TODO: +struct URI {}; + +struct WorkspaceFolder { + /// The associated URI for this workspace folder. + URI uri; + + /// The name of the workspace folder. Used to refer to this + /// workspace folder in the user interface. + std::string name; +}; + +struct InitializeParams { + /// The process Id of the parent process that started the server. Is null if + /// the process has not been started by another process. If the parent + /// process is not alive then the server should exit (see exit notification) + /// its process. + std::optional processId; + + struct ClientInfo { + std::string_view name; + std::optional version; + }; + + /// Information about the client + std::optional clientInfo; + + /// The locale the client is currently showing the user interface + /// in. This must not necessarily be the locale of the operating + /// system. + /// + /// Uses IETF language tags as the value's syntax + /// (See https://en.wikipedia.org/wiki/IETF_language_tag) + /// + /// @since 3.16.0 + std::optional locale; + + /// User provided initialization options. + /// TODO: initializationOptions?: LSPAny; + + /// The capabilities provided by the client (editor or tool). + ClientCapabilities capabilities; + + /// The initial trace setting. If omitted trace is disabled ('off'). + /// TODO: trace?: TraceValue; + + /// The workspace folders configured in the client when the server starts. + /// This property is only available if the client supports workspace folders. + /// It can be `null` if the client supports workspace folders but none are + /// configured. + std::optional> workspaceFolders; +}; + +/*===========================================================================// +// RESPONSES // +//===========================================================================*/ + +struct PositionEncodingKind { + /// Character offsets count UTF-8 code units (e.g bytes). + constexpr inline static std::string_view UTF8 = "utf-8"; + + /// Character offsets count UTF-16 code units. + /// This is the default and must always be supported by servers. + constexpr inline static std::string_view UTF16 = "utf-16"; + + /// Character offsets count UTF-32 code units. + /// Implementation note: these are the same as Unicode code points, + /// so this `PositionEncodingKind` may also be used for an + /// encoding-agnostic representation of character offsets. + constexpr inline static std::string_view UTF32 = "utf-32"; +}; + +/// Defines how the host (editor) should sync document changes to the language server. +enum class TextDocumentSyncKind { + /// Documents should not be synced at all. + None = 0, + + /// Documents are synced by always sending the full content of the document. + Full = 1, + + /// Documents are synced by sending the full content on open. After that only + /// incremental updates to the document are sent. + Incremental = 2, +}; + +/// Completion options. +struct CompletionOptions { + /// + /// The additional characters, beyond the defaults provided by the client (typically + ///[a-zA-Z]), that should automatically trigger a completion request. For example + ///`.` in JavaScript represents the beginning of an object property or method and is + /// thus a good candidate for triggering a completion request. + /// + /// Most tools trigger a completion request automatically without explicitly + /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they + /// do so when the user starts to type an identifier. For example if the user + /// types `c` in a JavaScript file code complete will automatically pop up + /// present `console` besides others as a completion item. Characters that + /// make up identifiers don't need to be listed here. + std::array triggerCharacters = {".", "<", ">", ":", "\"", "/", "*"}; + + /// The list of all possible characters that commit a completion. This field + /// can be used if clients don't support individual commit characters per + /// completion item. See client capability `completion.completionItem.commitCharactersSupport`. + /// + /// If a server provides both `allCommitCharacters` and commit characters on + /// an individual completion item the ones on the completion item win. + /// + /// allCommitCharacters?: string[]; + /// NOTICE: We don't set `(` etc as allCommitCharacters as they interact poorly with snippet results. + /// See https://github.com/clangd/vscode-clangd/issues/357 + /// Hopefully we can use them one day without this side-effect: + /// https://github.com/microsoft/vscode/issues/42544 + + /// The server provides support to resolve additional information for a completion item. + bool resolveProvider = false; + + /// The server supports the following `CompletionItem` specific capabilities. + /// TODO: completionItem?: {...} +}; + +struct SignatureHelpOptions { + /// The characters that trigger signature help automatically. + std::array triggerCharacters = {"(", ")", "{", "}", "<", ">", ","}; + + /// List of characters that re-trigger signature help. + /// These trigger characters are only active when signature help is already showing. + /// All trigger characters are also counted as re-trigger characters. + std::array retriggerCharacters = {","}; +}; + +struct CodeLensOptions { + /// Code lens has a resolve provider as well. + bool resolveProvider = false; +}; + +struct DocumentLinkOptions { + /// Document links have a resolve provider as well. + bool resolveProvider = false; +}; + +struct DocumentOnTypeFormattingOptions { + /// A character on which formatting should be triggered, like `{`. + std::string_view firstTriggerCharacter = "\n"; + + /// More trigger characters. + /// moreTriggerCharacter?: string[]; +}; + +struct SemanticTokensOptions { + /// The legend used by the server + protocol::SemanticTokensLegend legend; + + /// Server supports providing semantic tokens for a specific range of a document. + bool range = false; // TODO: further check + + struct Full { + /// Server supports providing semantic tokens for a full document. + bool delta = true; + }; + + /// Server supports providing semantic tokens for a full document. + Full full; +}; + +struct ServerCapabilities { + /// The position encoding the server picked from the encodings offered + /// by the client via the client capability `general.positionEncodings`. + /// + /// If the client didn't provide any position encodings the only valid + /// value that a server can return is 'utf-16'. + /// + /// If omitted it defaults to 'utf-16'. + /// + /// possible values: ['utf-8', 'utf-16', 'utf-32'] in PositionEncodingKind + std::string_view positionEncoding = PositionEncodingKind::UTF16; + + /// Defines how text documents are synced. Is either a detailed structure + /// defining each notification or for backwards compatibility the + /// TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`. + TextDocumentSyncKind textDocumentSync = TextDocumentSyncKind::Incremental; + + /// Defines how notebook documents are synced. + /// TODO: notebookDocumentSync?: NotebookDocumentSyncOptions | NotebookDocumentSyncRegistrationOptions; + + /// The server provides completion support. + CompletionOptions completionProvider; + + /// The server provides hover support. + bool hoverProvider = true; + + /// The server provides signature help support. + SignatureHelpOptions signatureHelpProvider; + + /// The server provides go to declaration support. + bool declarationProvider = true; + + /// The server provides goto definition support. + bool definitionProvider = true; + + /// The server provides goto type definition support. + bool typeDefinitionProvider = true; + + /// The server provides goto implementation support. + bool implementationProvider = true; + + /// The server provides find references support. + bool referencesProvider = true; + + /// The server provides document highlight support. + bool documentHighlightProvider = true; + + /// The server provides document symbol support. + bool documentSymbolProvider = true; + + /// The server provides code actions. The `CodeActionOptions` return type is + /// only valid if the client signals code action literal support via the + /// client capability `textDocument.codeAction.codeActionLiteralSupport`. + bool codeActionProvider = true; // TODO: provide CodeActionOptions + + /// The server provides code lens. + CodeLensOptions codeLensProvider; + + /// The server provides document link support. + DocumentLinkOptions documentLinkProvider; + + /// The server provides color provider support. + bool colorProvider = false; // TODO: check what is colorProvider + + /// The server provides document formatting. + bool documentFormattingProvider = true; + + /// The server provides document range formatting. + bool documentRangeFormattingProvider = true; + + /// The server provides document formatting on typing. + DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; + + /// The server provides rename support. RenameOptions may only be + /// specified if the client states that it supports + /// `prepareSupport` in its initial `initialize` request. + bool renameProvider = true; + + /// The server provides folding provider support. + bool foldingRangeProvider = true; + + /// The server provides execute command support. + /// executeCommandProvider?: ExecuteCommandOptions; + + /// The server provides selection range support. + bool selectionRangeProvider = true; + + /// The server provides linked editing range support. + bool linkedEditingRangeProvider = true; + + /// The server provides call hierarchy support. + bool callHierarchyProvider = true; + + /// The server provides semantic tokens support. + SemanticTokensOptions semanticTokensProvider; + + /// Whether server provides moniker support. + bool monikerProvider = false; // TODO: further discussion + + /// The server provides type hierarchy support. + bool typeHierarchyProvider = true; + + /// The server provides inline values. + bool inlineValueProvider = true; + + /// The server provides inlay hints. + bool inlayHintProvider = true; + + /// The server has support for pull model diagnostics. + /// TODO: diagnosticProvider?: DiagnosticOptions + + /// The server provides workspace symbol support. + bool workspaceSymbolProvider = true; + + /// The server is interested in file notifications/requests. + /// TODO: fileOperations?: {...} +}; + +struct InitializeResult { + /// The capabilities the language server provides. + ServerCapabilities capabilities; + + struct ServerInfo { + /// The name of the server as defined by the server. + std::string_view name = "clice"; + + /// The server's version as defined by the server. + std::string_view version = "0.0.1"; + }; + + /// Information about the server. + ServerInfo serverInfo; +}; + +/*===================================================/ +/ / +/======= Text Document Synchronization ==========/ +/ / +/===================================================*/ + +/// An item to transfer a text document from the client to the server. +struct TextDocumentItem { + /// The text document's URI. + std::string_view uri; + + /// The text document's language identifier. + std::string_view languageId; + + /// he version number of this document (it will increase after each change, including undo/redo). + int version; + + /// The content of the opened text document. + std::string_view text; +}; + +/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. +struct TextDocumentIdentifier { + /// The text document's URI. + std::string_view uri; +}; + +struct VersionedTextDocumentIdentifier { + /// The text document's URI. + std::string_view uri; + + /// The version number of this document. + /// + /// The version number of a document will increase after each change, + /// including undo/redo. The number doesn't need to be consecutive. + int version; +}; + +struct DidOpenTextDocumentParams { + /// The document that was opened. + TextDocumentItem textDocument; +}; + +struct TextDocumentContentChangeEvent { + // TODO: +}; + +struct DidChangeTextDocumentParams { + /// The document that did change. The version number points + /// to the version after all provided content changes have + /// been applied. + VersionedTextDocumentIdentifier textDocument; + + /// The actual content changes. The content changes describe single state + /// changes to the document. So if there are two content changes c1 (at + /// array index 0) and c2 (at array index 1) for a document in state S then + /// c1 moves the document from S to S' and c2 from S' to S''. So c1 is + /// computed on the state S and c2 is computed on the state S'. + /// + /// To mirror the content of a document using change events use the following + /// approach: + /// - start with the same initial content + /// - apply the 'textDocument/didChange' notifications in the order you receive them. + /// - apply the `TextDocumentContentChangeEvent`s in a single notification in the order you receive them. + std::vector contentChanges; +}; + +struct DidCloseTextDocumentParams { + /// The document that was closed. + TextDocumentIdentifier textDocument; +}; + +struct DidSaveTextDocumentParams { + /// The document that was saved. + TextDocumentIdentifier textDocument; + + /// Optional the content when saved. Depends on the includeText value + /// when the save notification was requested. + std::optional text; +}; + +} // namespace clice diff --git a/include/Server/Scheduler .h b/include/Server/Scheduler .h index eb33f2c6..e6d6ccd8 100644 --- a/include/Server/Scheduler .h +++ b/include/Server/Scheduler .h @@ -19,6 +19,8 @@ private: public: void update(std::string_view path, std::string_view content); + void dispatch(json::Value&& params); + private: llvm::StringMap files; }; diff --git a/include/Server/Server.h b/include/Server/Server.h index 8be75c66..19dfd1b3 100644 --- a/include/Server/Server.h +++ b/include/Server/Server.h @@ -3,23 +3,35 @@ #include #include #include +#include namespace clice { -class Server { -public: +struct Server { + int argc; + const char** argv; + + using Handler = llvm::unique_function; + + Option option; + Scheduler scheduler; + CompilationDatabase CDB; + llvm::StringMap handlers; + + static Server instance; + + Server(); + int run(int argc, const char** argv); void handleMessage(std::string_view message); -private: - Option option; - Scheduler scheduler; - CompilationDatabase CDB; +public: + // LSP methods, if the return type is void, the method is used for notification. + // otherwise, the method is used for request. + auto initialize(protocol::InitializeParams params) -> protocol::InitializeResult; + + void initialized(protocol::InitializedParams params); }; -namespace global { -extern Server server; -} - } // namespace clice diff --git a/include/Support/Reflection.h b/include/Support/Reflection.h index f34cc647..cf075966 100644 --- a/include/Support/Reflection.h +++ b/include/Support/Reflection.h @@ -60,7 +60,9 @@ constexpr auto member_name() { template constexpr auto collcet_members(Object&& object) { // clang-format off - if constexpr(count == 1) { + if constexpr(count == 0) { + return std::tuple{}; + } else if constexpr(count == 1) { auto&& [a] = object; return std::tuple{&a}; } else if constexpr(count == 2) { diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index 46a51f08..71cfab33 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -6,10 +6,11 @@ #include #include #include -#include namespace clice { +Server Server::instance; + static uv_loop_t* loop; static uv_pipe_t stdin_pipe; static uv_pipe_t stdout_pipe; @@ -58,7 +59,8 @@ void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if(nread > 0) { buffer.write(std::string_view(buf->base, nread)); if(auto message = buffer.read(); !message.empty()) { - global::server.handleMessage(message); + Server::instance.handleMessage(message); + buffer.clear(); } } else if(nread < 0) { if(nread != UV_EOF) { @@ -68,13 +70,65 @@ void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { } } +Server::Server() { + handlers.try_emplace("initialize", [](json::Value& id, json::Value& value) { + auto params = value.getAsObject(); + auto result = instance.initialize(json::deserialize(*params)); + + json::Object response; + response.try_emplace("jsonrpc", "2.0"); + response.try_emplace("id", id); + response.try_emplace("result", json::serialize(result)); + + json::Value responseValue = std::move(response); + + std::string s; + llvm::raw_string_ostream stream(s); + stream << responseValue; + stream.flush(); + + s = "Content-Length: " + std::to_string(s.size()) + "\r\n\r\n" + s; + + static uv_buf_t buf = uv_buf_init(s.data(), s.size()); + static uv_write_t req; + auto state = uv_write(&req, (uv_stream_t*)&stdout_pipe, &buf, 1, NULL); + if(state < 0) { + spdlog::error("Error writing to stdout: {}", uv_strerror(state)); + } + }); +} + +auto Server::initialize(protocol::InitializeParams params) -> protocol::InitializeResult { + // TODO: + return protocol::InitializeResult(); +} + int Server::run(int argc, const char** argv) { + std::this_thread::sleep_for(std::chrono::seconds(5)); + argc = argc; + argv = argv; // set logger llvm::SmallString<128> temp; - temp.append(path::parent_path((path::parent_path(argv[0])))); + // 获取父路径 + temp.append(path::parent_path(path::parent_path(argv[0]))); path::append(temp, "logs"); + + // 确保路径绝对化 auto error = llvm::sys::fs::make_absolute(temp); - path::append(temp, "clice.log"); + + // 获取当前时间并格式化为字符串 + auto now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + std::tm now_tm = *std::localtime(&now_c); + + std::ostringstream timeStream; + timeStream << std::put_time(&now_tm, "%Y-%m-%d_%H-%M-%S"); // 格式化为 "YYYY-MM-DD_HH-MM-SS" + + // 将时间戳加入到日志文件名 + std::string logFileName = "clice_" + timeStream.str() + ".log"; + path::append(temp, logFileName); + + // 创建 logger auto logger = spdlog::basic_logger_mt("clice", std::string(temp.str())); logger->flush_on(spdlog::level::trace); spdlog::set_default_logger(logger); @@ -104,34 +158,14 @@ void Server::handleMessage(std::string_view message) { spdlog::info("Received message: {}", message); auto input = result->getAsObject(); auto id = input->get("id"); - auto method = input->get("method"); + std::string_view method = input->get("method")->getAsString().value(); auto params = input->get("params"); - json::Object response; - response.try_emplace("jsonrpc", "2.0"); - response.try_emplace("id", *id); - response.try_emplace("result", json::serialize(protocol::InitializeResult{})); - - llvm::json::Value responseValue = std::move(response); - - std::string s; - llvm::raw_string_ostream stream(s); - stream << responseValue; - stream.flush(); - - s = "Content-Length: " + std::to_string(s.size()) + "\r\n\r\n" + s; - - uv_buf_t buf = uv_buf_init(s.data(), s.size()); - uv_write_t req; - auto state = uv_write(&req, (uv_stream_t*)&stdout_pipe, &buf, 1, NULL); - if(state < 0) { - spdlog::error("Error writing to stdout: {}", uv_strerror(state)); + if(auto handler = handlers.find(method); handler != handlers.end()) { + handler->second(*id, *params); + } else { + spdlog::error("Method not found: {}", method); } - spdlog::info("Sent message: {}", s); -} - -namespace global { -Server server; } } // namespace clice diff --git a/src/main.cpp b/src/main.cpp index aae1a38e..2ee6fe9a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include int main(int argc, const char** argv) { - using namespace clice::global; - return server.run(argc, argv); + using namespace clice; + return Server::instance.run(argc, argv); }