### Start an LSP Session with lsp-test Source: https://github.com/haskell/lsp/blob/master/README.md Example of setting up and running a language server test session using the lsp-test library. It shows how to open a document, skip notifications, and retrieve document symbols. ```haskell import Language.LSP.Test main = runSession "hie" fullCaps "proj/dir" $ do doc <- openDoc "Foo.hs" "haskell" skipMany anyNotification symbols <- getDocumentSymbols doc ``` -------------------------------- ### Configuration Update Callback Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/configuration.md An example of the `onConfigChange` callback, showing how to react to configuration updates by enabling or disabling debug logging. ```haskell onConfigChange :: Config -> IO () onConfigChange cfg = do -- React to configuration change case debugMode cfg of True -> enableDebugLogging False -> disableDebugLogging ``` -------------------------------- ### runSession Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Demonstrates how to use the `runSession` function to execute tests within an LSP session. This includes opening documents, skipping notifications, and performing actions like getting hover information. ```APIDOC ## runSession Example ### Description An example demonstrating the usage of `runSession` for testing LSP functionality, including opening documents, retrieving hover information, and checking diagnostics. ### Usage ```haskell runSession :: FilePath -> FilePath -> FilePath -> Session a -> IO a ``` ### Example Usage in Test Suite ```haskell runSession "hie" fullLatestClientCaps "." $ do doc <- openDoc "Main.hs" "haskell" skipMany anyNotification let pos = Position 5 10 hover <- getHover doc pos liftIO $ hover `shouldNotBe` Nothing ``` ``` -------------------------------- ### Method Type Examples Source: https://github.com/haskell/lsp/blob/master/lsp-types/ChangeLog.md Provides examples of Method types, illustrating how they are parameterized by direction (FromClient/FromServer) and message type (Request/Notification). ```haskell TextDocumentFoldingRange :: Method FromClient Request TextDocumentSelectionRange :: Method FromClient Request WindowShowMessage :: Method FromServer Notification WindowShowMessageRequest :: Method FromServer Request ``` -------------------------------- ### Multi-Source Diagnostic Server Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/diagnostics.md A complete example of an LSP server handler that runs multiple analyses (syntax and style) and publishes diagnostics from each source independently. ```haskell module DiagnosticServer where import Language.LSP.Server import Language.LSP.Diagnostics import Language.LSP.Protocol.Types import Language.LSP.Protocol.Lens qualified as L handlers :: Handlers (LspM ()) handlers = mconcat [ requestHandler SMethod_TextDocumentDidOpen $ \req _responder -> do let params = req ^. L.params let uri = params ^. L.textDocument . L.uri let normalizedUri = toNormalizedUri uri -- Run multiple analyses let syntaxErrors = runSyntaxAnalysis uri let styleWarnings = runStyleAnalysis uri -- Publish from different sources publishDiagnostics normalizedUri (Just "syntax") syntaxErrors publishDiagnostics normalizedUri (Just "style") styleWarnings ] ``` -------------------------------- ### Rope Usage Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Demonstrates basic usage of the Rope type for text operations, including getting file content, its length, and taking a substring. ```haskell import Data.Text.Utf16.Rope.Mixed qualified as Rope vf <- getVirtualFile uri let content = vf ^. file_text let length = Rope.length content let substring = Rope.take 100 content ``` -------------------------------- ### Initialized Notification Handler Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md An example of using notificationHandler to register a handler for the SMethod_Initialized notification, printing a message to the console. ```haskell notificationHandler SMethod_Initialized $ \notif -> do liftIO $ putStrLn "Server initialized" ``` -------------------------------- ### VFS Initialization and File Opening Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Example of initializing an empty VFS and then opening a new file with specified URI, version, language, and content. ```haskell import Language.LSP.VFS import Language.LSP.Server -- Initialize VFS let vfs = emptyVFS -- Open a file let vfs' = openVFS (toNormalizedUri "file:///test.hs") 0 (Just LanguageKind_Haskell) "module Test where" vfs ``` -------------------------------- ### Example Usage of withProgress Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Demonstrates how to use the `withProgress` function to report progress with updates and a title. ```haskell withProgress "Analyzing files" Nothing Cancellable $ \update -> do update (ProgressAmount (Just 25) (Just "Step 1")) -- ... do work update (ProgressAmount (Just 50) (Just "Step 2")) -- ... return result ``` -------------------------------- ### LSP Server Configuration with Custom Headers Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Example of configuring a server to use a custom header parsing function. ```haskell runServerWithConfig ServerConfig { parseInwards = parseHeaders , prepareOutwards = prependHeader , ... } ``` -------------------------------- ### withWebsocketRunServer Function Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md A convenience function that combines the setup of a WebSocket server with running the LSP server. It simplifies the process of starting an LSP server over WebSockets. ```APIDOC ## withWebsocketRunServer ### Description Convenience combining `withWebsocket` and `runServerWith`. ### Parameters - `LogAction IO (WithSeverity LspServerLog)` - IO logger - `WebsocketConfig` - WebSocket configuration - `LogAction (LspM config) (WithSeverity LspServerLog)` - LSP logger - `ServerDefinition config` - Server configuration ### Returns `IO ()` — Blocks until shutdown ``` -------------------------------- ### Create Empty VFS Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Initializes an empty VFS with no files. Use this to start a new virtual file system. ```haskell emptyVFS :: VFS ``` -------------------------------- ### Build a Simple Haskell Language Server Source: https://github.com/haskell/lsp/blob/master/README.md Example of building a basic language server using the lsp library. It demonstrates handling initialization, notifications, and requests, including dynamic capability registration for code lenses and hover information. ```haskell {-# LANGUAGE DuplicateRecordFields #} {-# LANGUAGE LambdaCase #} {-# LANGUAGE OverloadedStrings #} import Control.Monad.IO.Class import Data.Text qualified as T import Language.LSP.Protocol.Message import Language.LSP.Protocol.Types import Language.LSP.Server handlers :: Handlers (LspM ()) handlers = mconcat [ notificationHandler SMethod_Initialized $ \_not -> do let params = ShowMessageRequestParams MessageType_Info "Turn on code lenses?" (Just [MessageActionItem "Turn on", MessageActionItem "Don't"]) _ <- sendRequest SMethod_WindowShowMessageRequest params $ \case Right (InL (MessageActionItem "Turn on")) -> do let regOpts = CodeLensRegistrationOptions (InR Null) Nothing (Just False) _ <- registerCapability mempty SMethod_TextDocumentCodeLens regOpts $ \_req responder -> do let cmd = Command "Say hello" "lsp-hello-command" Nothing rsp = [CodeLens (mkRange 0 0 0 100) (Just cmd) Nothing] responder $ Right $ InL rsp pure () Right _ -> sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Info "Not turning on code lenses") Left err -> sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Error $ "Something went wrong!\n" <> T.pack (show err)) pure () , requestHandler SMethod_TextDocumentHover $ \req responder -> do let TRequestMessage _ _ _ (HoverParams _doc pos _workDone) = req Position _l _c' = pos rsp = Hover (InL ms) (Just range) ms = mkMarkdown "Hello world" range = Range pos pos responder (Right $ InL rsp) ] main :: IO Int main = runServer $ ServerDefinition { parseConfig = const $ const $ Right () , onConfigChange = const $ pure () , defaultConfig = () , configSection = "demo" , doInitialize = \env _req -> pure $ Right env , staticHandlers = \_caps -> handlers , interpretHandler = \env -> Iso (runLspT env) liftIO , options = defaultOptions } ``` -------------------------------- ### Testing a Haskell LSP Server Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md This example shows how to test an LSP server using the `lsp-test` library. It covers opening a document, sending a hover request, and verifying the response. ```haskell {-# LANGUAGE OverloadedStrings #} import Language.LSP.Test import Language.LSP.Protocol.Capabilities import Language.LSP.Protocol.Types main :: IO () main = do runSession "my-server" fullLatestClientCaps "." $ do doc <- openDoc "Main.hs" "haskell" -- Send hover request let pos = Position 0 0 hover <- request SMethod_TextDocumentHover (HoverParams doc pos Nothing) -- Check response case hover of Right (InL (Hover _ _)) -> liftIO $ putStrLn "Success" _ -> liftIO $ putStrLn "Failed" closeDoc doc ``` -------------------------------- ### LspT Handler Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md An example of defining a handler within the LspT monad for a hover request. It demonstrates accessing client capabilities and preparing a response. ```haskell import Language.LSP.Server -- Define custom config type data Config = Config { debug :: Bool } -- Handler in LspT myHandler :: Handler (LspT Config IO) SMethod_TextDocumentHover myHandler req responder = do caps <- getClientCapabilities -- ... respond to hover request ``` -------------------------------- ### emptyVFS Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Creates an empty VFS with no files. This is the starting point for a new virtual file system. ```APIDOC ## emptyVFS ### Description Create an empty VFS with no files. ### Returns `VFS` — Empty virtual file system ``` -------------------------------- ### ServerDefinition with interpretHandler Source: https://github.com/haskell/lsp/blob/master/lsp-types/ChangeLog.md Example of how to configure ServerDefinition, specifically the interpretHandler to convert between IO and your custom monad for running LspT. ```haskell type ServerDefinition { ... , doInitialize = \env _req -> pure $ Right env , interpretHandler = \env -> Iso (runLspT env) -- how to convert from IO ~> m liftIO -- how to convert from m ~> IO } ``` -------------------------------- ### Haskell LSP Sending Requests to Client Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Shows how to send a request to the LSP client and handle its response. This example sends a `window/showMessageRequest` and processes the user's choice. ```haskell sendRequest SMethod_WindowShowMessageRequest (ShowMessageRequestParams MessageType_Info "Continue?" Nothing) $ \case Right (InL (MessageActionItem "Yes")) -> putStrLn "User chose yes" Right _ -> putStrLn "User chose something else" Left err -> putStrLn $ "Request failed: " ++ show err ``` -------------------------------- ### Get Server Configuration Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Fetch the current server configuration object. This allows the server to access its runtime settings. ```haskell getConfig :: MonadLsp config m => m config ``` -------------------------------- ### Create Source-Specific Loggers Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/logging.md Example of creating distinct loggers for different sources (e.g., Analyzer, Checker) by prepending source information to log messages before sending them via the default client logger. ```haskell import Language.LSP.Logging data LogSource = Analyzer | Checker | Formatter deriving (Show) -- Create source-specific loggers analyzerLog :: (MonadLsp c m) => LogAction m (WithSeverity Text) analyzerLog = LogAction $ \(WithSeverity msg sev) -> defaultClientLogger <& ("[Analyzer] " <> msg) `WithSeverity` sev checkerLog :: (MonadLsp c m) => LogAction m (WithSeverity Text) checkerLog = LogAction $ \(WithSeverity msg sev) -> defaultClientLogger <& ("[Checker] " <> msg) `WithSeverity` sev -- Use in handlers handler :: Handler (LspM Config) SMethod_TextDocumentDidOpen handler req _responder = do analyzerLog <& "Starting analysis" `WithSeverity` Info -- ... do work checkerLog <& "Type checking complete" `WithSeverity` Info ``` -------------------------------- ### Create a ResponseError Instance Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Example of creating a `ResponseError` for invalid parameters and sending it as a response. ```haskell import Language.LSP.Protocol.Types let err = ResponseError ErrorCode_InvalidParams "Missing required parameter" Nothing responder (Left err) ``` -------------------------------- ### Haskell LSP Configuration Handling Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Defines a custom configuration structure for the LSP server using `aeson` for JSON parsing. This example shows how to define `Config` with `debugMode` and `checkInterval` fields and integrate it into `ServerDefinition`. ```haskell {-# LANGUAGE DeriveGeneric #} import Data.Aeson import GHC.Generics data Config = Config { debugMode :: Bool , checkInterval :: Int } deriving (Generic, FromJSON, ToJSON) myServer :: ServerDefinition Config myServer = ServerDefinition { defaultConfig = Config False 1000 , configSection = "myserver" , parseConfig = \_ val -> case fromJSON val of Success cfg -> Right cfg Error msg -> Left (T.pack msg) , onConfigChange = \cfg -> liftIO $ do putStrLn $ "Config updated: " ++ show cfg , ... } ``` -------------------------------- ### Get Entire Virtual File System Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Obtain a complete snapshot of all currently open virtual files in the VFS. ```haskell getVirtualFiles :: MonadLsp config m => m VFS ``` -------------------------------- ### Clear and Publish Diagnostics Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/diagnostics.md Provides examples for clearing all diagnostics associated with a specific source for a file and for publishing new diagnostic information. ```haskell -- Clear all diagnostics for a file publishDiagnostics uri (Just "myanalyzer") [] -- Publish new diagnostics publishDiagnostics uri (Just "myanalyzer") newDiags ``` -------------------------------- ### Get Client Capabilities Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Retrieve the capabilities that the client reported during the initialization handshake. This information is crucial for understanding what features the client supports. ```haskell getClientCapabilities :: MonadLsp config m => m ClientCapabilities ``` -------------------------------- ### Example parseConfig Function Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md A sample `parseConfig` function that returns `Left` with an error message, triggering a `ConfigurationParseError` log. ```haskell parseConfig :: Config -> J.Value -> Either Text Config parseConfig old val = case fromJSON val of Error msg -> Left (T.pack msg) -- Triggers ConfigurationParseError log Success cfg -> Right cfg ``` -------------------------------- ### Convenience Function for WebSocket LSP Server Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Combines WebSocket setup and server execution into a single function for ease of use. ```haskell withWebsocketRunServer :: LogAction IO (WithSeverity LspServerLog) -> WebsocketConfig -> LogAction (LspM config) (WithSeverity LspServerLog) -> ServerDefinition config -> IO () ``` -------------------------------- ### Singleton Method Type Examples Source: https://github.com/haskell/lsp/blob/master/lsp-types/ChangeLog.md Shows singleton counterparts for Method types, used at the term level for specifying methods in messages like RequestMessage. ```haskell STextDocumentFoldingRange :: SMethod TextDocumentFoldingRange STextDocumentSelectionRange :: SMethod TextDocumentSelectionRange SWindowShowMessage :: SMethod WindowShowMessage SWindowShowMessageRequest :: SMethod WindowShowMessageRequest ``` -------------------------------- ### Haskell LSP Sending Notifications to Client Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Demonstrates sending different types of notifications to the LSP client. Includes examples for showing messages and publishing diagnostics. ```haskell sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Warning "This is a warning") sendNotification SMethod_TextDocumentPublishDiagnostics (PublishDiagnosticsParams uri version diagnostics) ``` -------------------------------- ### Setting up WebSocket Server for LSP Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Demonstrates how to initialize a WebSocket server and run an LSP server over it, providing input and output handlers. ```haskell withWebsocket defaultIOLogger (WebsocketConfig "localhost" 8080) $ \inwards outwards -> runServerWith defaultIOLogger defaultLspLogger inwards outwards serverDef ``` -------------------------------- ### Setting Progress Reporting Delays Source: https://github.com/haskell/lsp/blob/master/_autodocs/configuration.md Configures the delays for starting progress UI and between progress updates to manage UI flicker for short operations. ```haskell defaultOptions { optProgressStartDelay = 500000 -- 500ms , optProgressUpdateDelay = 250000 -- 250ms } ``` -------------------------------- ### runSessionWithConfigCustomProcess Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Launches an LSP test session using a custom process creation configuration. This is useful when the server executable is not in the system's PATH or requires specific startup arguments. ```APIDOC ## runSessionWithConfigCustomProcess ### Description Run a session with custom process creation. ### Method N/A (Function Signature) ### Endpoint N/A (Function Signature) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example N/A ### Response #### Success Response (200) N/A (Function Returns IO a) #### Response Example N/A ``` -------------------------------- ### Define Range Source: https://github.com/haskell/lsp/blob/master/_autodocs/types.md Defines a range within a text document, specified by a start and end position. The start is inclusive, and the end is exclusive. ```haskell data Range = Range { _start :: Position , _end :: Position } ``` -------------------------------- ### Run LSP Server with Full Configuration Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Use `runServerWithConfig` when you require complete control over the server's I/O pipeline and message parsing. It takes a detailed `ServerConfig` and the server definition. ```haskell runServerWithConfig :: ServerConfig config -> ServerDefinition config -> IO Int ``` -------------------------------- ### Type Union Patterns with Either and |+| Source: https://github.com/haskell/lsp/blob/master/_autodocs/types.md Explains how LSP uses type unions, specifically with `Either` (using `InL`/`InR`) and the `|+|` operator for multiple alternatives. Provides an example of pattern matching on a union type. ```haskell -- Either type: data TextEdit = TextEdit { _range :: Range, _newText :: Text } -- Or using (|+|) for multiple alternatives: _contents :: MarkupContent | MarkedString | [MarkedString] -- Pattern match with InL, InR: case contents of InL markup -> handleMarkup markup InR string -> handleString string ``` -------------------------------- ### Unit Test Diagnostics with HSpec Source: https://github.com/haskell/lsp/blob/master/lsp-test/README.md Example of writing unit tests for diagnostics using HSpec. It runs an LSP session, opens a file with errors, waits for diagnostics from a specific source, and asserts their severity and source. ```haskell describe "diagnostics" $ it "report errors" $ runSession "hie" fullLatestClientCaps "test/data" $ do openDoc "Error.hs" "haskell" [diag] <- waitForDiagnosticsSource "ghcmod" liftIO $ do diag ^. severity `shouldBe` Just DsError diag ^. source `shouldBe` Just "ghcmod" ``` -------------------------------- ### TextDocumentHover Request Handler Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md An example of using requestHandler to register a handler for the SMethod_TextDocumentHover request. It extracts parameters, creates a Hover response, and uses the responder function. ```haskell requestHandler SMethod_TextDocumentHover $ \req responder -> do let params = case req of TRequestMessage _ _ _ p -> p let rsp = Hover (InL (mkMarkdown "Hover text")) Nothing responder (Right rsp) ``` -------------------------------- ### Get Current Diagnostics Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Retrieves the current diagnostics for a specific document. ```haskell getCurrentDiagnostics :: TextDocumentIdentifier -> Session [Diagnostic] ``` -------------------------------- ### Registering Capabilities with Client Check Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Demonstrates how to check client capabilities before attempting to register a dynamic capability, preventing potential registration failures. ```haskell -- Check client capabilities before registering mToken <- registerCapability mempty SMethod_TextDocumentCodeLens regOpts handler case mToken of Nothing -> putStrLn "Client doesn't support code lens" Just token -> putStrLn "Code lens registered" ``` -------------------------------- ### Get Reference Locations Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests all references to a symbol at a given position. ```haskell getReferences :: TextDocumentIdentifier -> Position -> Session [Location] ``` -------------------------------- ### Run LSP Test Session with Custom Process Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use runSessionWithConfigCustomProcess when the server is not in PATH or requires special startup configuration. It allows specifying custom process creation parameters along with configuration and capabilities. ```haskell runSessionWithConfigCustomProcess :: SessionConfig -> CreateProcess -> ClientCapabilities -> FilePath -> Session a -> IO a ``` -------------------------------- ### Catch UnexpectedResponseError Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Example of catching an `UnexpectedResponseError` from a `request` and printing the error message. ```haskell request method params `catch` \(UnexpectedResponseError err) -> do liftIO $ print $ err ^. message ``` -------------------------------- ### runServerWithConfig Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Run an LSP server with a complete I/O configuration object. This is for scenarios requiring full control over the I/O pipeline and message parsing. ```APIDOC ## runServerWithConfig ### Description Run server with complete I/O configuration. This is for scenarios requiring full control over the I/O pipeline and message parsing. ### Method ```haskell runServerWithConfig :: ServerConfig config -> ServerDefinition config -> IO Int ``` ### Parameters - `ServerConfig config` - I/O configuration - `ServerDefinition config` - Server configuration ### Returns - `IO Int` - Exit code ### Use when You need complete control over I/O or message parsing. ``` -------------------------------- ### Get Completions Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests available completion items at a specific position in a document. ```haskell getCompletions :: TextDocumentIdentifier -> Position -> Session [CompletionItem] ``` -------------------------------- ### Good Practice: Handling Configuration Errors Gracefully Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Shows how to handle configuration parsing errors by falling back to the old configuration, preventing server instability. ```haskell -- ✓ Good parseConfig :: Config -> J.Value -> Either Text Config parseConfig old val = fromJSON val & \case Success cfg -> Right cfg Error msg -> Right old -- Keep old config on parse error ``` -------------------------------- ### Get Definition Locations Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests all definition locations for a symbol at a given position. ```haskell getDefinitions :: TextDocumentIdentifier -> Position -> Session [Location] ``` -------------------------------- ### Get Document Symbols Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests document symbols (outline) for a given document. ```haskell getDocumentSymbols :: TextDocumentIdentifier -> Session [DocumentSymbol] ``` -------------------------------- ### Get Workspace Folders Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Retrieves the list of workspace folders opened by the client. ```haskell getWorkspaceFolders :: MonadLsp config m => m [WorkspaceFolder] ``` -------------------------------- ### Uncaught Exception in Handler Example Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Illustrates an uncaught exception within a `requestHandler` for `SMethod_TextDocumentHover`. ```haskell requestHandler SMethod_TextDocumentHover $ \req responder -> do error "Unhandled error in handler" -- Will be caught and logged ``` -------------------------------- ### Language.LSP.Server.Core Source: https://github.com/haskell/lsp/blob/master/_autodocs/MANIFEST.txt Documentation for the core LspT monad, handlers, and client communication primitives. ```APIDOC ## Core Server Functionality This module provides the fundamental types and functions for building an LSP server. ### Types - **LspT**: The monad transformer for LSP computations. - **LspM**: A type alias for `LspT IO`. - **Handlers**: A type representing a collection of handlers for LSP messages. - **Handler**: A type family for defining handlers. - **MonadLsp**: A type class for monads that support LSP operations. ### Functions - **runLspT**: Runs an `LspT` computation. - **sendRequest**: Sends a request to the client. - **sendNotification**: Sends a notification to the client. - **openVFS**: Opens a virtual file system. - **closeVFS**: Closes a virtual file system. - **updateDiagnostics**: Updates diagnostics in the client. - **registerCapability**: Dynamically registers a capability with the client. - **shutdown**: Manages server shutdown. ``` -------------------------------- ### runSession Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Runs a test session against an LSP server by launching it as a subprocess. It initializes the server with provided capabilities and manages the session lifecycle. ```APIDOC ## runSession ### Description Run a test session against an LSP server. ### Method N/A (Function Signature) ### Endpoint N/A (Function Signature) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```haskell import Language.LSP.Test import Language.LSP.Protocol.Capabilities runSession "hie" fullLatestClientCaps "." $ do doc <- openDoc "Main.hs" "haskell" diags <- waitForDiagnostics liftIO $ diags `shouldNotBe` [] ``` ### Response #### Success Response (200) N/A (Function Returns IO a) #### Response Example N/A ``` -------------------------------- ### Range Source: https://github.com/haskell/lsp/blob/master/_autodocs/types.md Defines a range within a text document, specified by a start and end position. ```APIDOC ## Range ### Description Range in a text document. ### Type Definition ```haskell data Range = Range { _start :: Position , _end :: Position } ``` ### Fields - `_start` (Position) - Start position (inclusive) - `_end` (Position) - End position (exclusive) ### Lenses - `start` - `end` ``` -------------------------------- ### Run LSP Session Source: https://github.com/haskell/lsp/blob/master/lsp-test/README.md Initiates an LSP session with a specified server, client capabilities, and project directory. It opens a document, skips notifications, and retrieves document symbols. ```haskell import Language.LSP.Test main = runSession "hie" fullLatestClientCaps "proj/dir" $ do doc <- openDoc "Foo.hs" "haskell" skipMany anyNotification symbols <- getDocumentSymbols doc ``` -------------------------------- ### runServerWith Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Run an LSP server with custom input and output functions. This provides flexibility by allowing the use of custom functions for reading and writing messages. ```APIDOC ## runServerWith ### Description Run a server with custom input and output functions. This provides flexibility by allowing the use of custom functions for reading and writing messages. ### Method ```haskell runServerWith :: LogAction IO (WithSeverity LspServerLog) -> LogAction (LspM config) (WithSeverity LspServerLog) -> IO BS.StrictByteString -> (BSL.LazyByteString -> IO ()) -> ServerDefinition config -> IO Int ``` ### Parameters - `LogAction IO (WithSeverity LspServerLog)` - Pre-initialization logger - `LogAction (LspM config) (WithSeverity LspServerLog)` - Post-initialization logger - `IO BS.StrictByteString` - Input function returning message bytes - `BSL.LazyByteString -> IO ()` - Output function for responses - `ServerDefinition config` - Server configuration ### Returns - `IO Int` - Exit code ### Note Automatically applies `prependHeader` and `parseHeaders` for standard LSP message framing. ``` -------------------------------- ### Get Hover Information Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests hover information at a specific position within a document. ```haskell getHover :: TextDocumentIdentifier -> Position -> Session (Maybe Hover) ``` -------------------------------- ### Server Info Configuration Source: https://github.com/haskell/lsp/blob/master/_autodocs/configuration.md Advertises the language server's name and version. ```haskell defaultOptions { optServerInfo = Just ServerInfo { _name = "My Language Server" , _version = Just "1.0.0" } } ``` -------------------------------- ### Closing a Virtual File Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Example of closing a virtual file from the VFS using the `closeVFS` function. ```haskell -- Close file let vfs''' = closeVFS uri vfs'' ``` -------------------------------- ### Run Simple Server with LspM Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Configures and runs a simple LSP server using the `LspM` monad for handling requests and notifications. ```haskell runServer $ ServerDefinition { ... , doInitialize = \env _req -> pure $ Right () , staticHandlers = \_ -> requestHandler method $ \req responder -> do -- Runs in LspM () caps <- getClientCapabilities responder $ Right result , interpretHandler = \() -> Iso id id } ``` -------------------------------- ### LSP Method Types Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Demonstrates the different types of LSP methods (notifications and requests) and how to use them with handlers. ```haskell -- Notification (no response) SMethod_Initialized SMethod_TextDocumentDidOpen SMethod_TextDocumentDidChange -- Request (requires response) SMethod_TextDocumentHover SMethod_TextDocumentCompletion SMethod_TextDocumentDefinition -- Use with handlers notificationHandler SMethod_Initialized handler requestHandler SMethod_TextDocumentHover handler ``` -------------------------------- ### Get Code Actions Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Requests available code actions for a specified range within a document. ```haskell getCodeActions :: TextDocumentIdentifier -> Range -> Session [CodeAction] ``` -------------------------------- ### Get Current Document Content Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use this function to retrieve the current content of an open document. ```haskell documentContents :: TextDocumentIdentifier -> Session Text ``` -------------------------------- ### Minimal Haskell LSP Server Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md This snippet demonstrates the basic structure for running a minimal LSP server in Haskell. It includes default configurations and basic handlers for initialization, hover requests, and showing messages. ```haskell {-# LANGUAGE OverloadedStrings #} import Language.LSP.Server import Language.LSP.Protocol.Message import Language.LSP.Protocol.Types main :: IO () main = runServer $ ServerDefinition { defaultConfig = () , configSection = "myserver" , parseConfig = const $ const $ Right () , onConfigChange = const $ pure () , doInitialize = \env _req -> pure $ Right env , staticHandlers = \_caps -> handlers , interpretHandler = \env -> Iso (runLspT env) liftIO , options = defaultOptions } handlers :: Handlers (LspM ()) handlers = mconcat [ notificationHandler SMethod_Initialized $ \_ -> sendNotification SMethod_WindowShowMessage (ShowMessageParams MessageType_Info "Server initialized") , requestHandler SMethod_TextDocumentHover $ \req responder -> do let hover = Hover (InL $ mkMarkdown "Hover text") Nothing responder (Right $ InL hover) ] ``` -------------------------------- ### Get Document URI Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use this function to obtain the Uniform Resource Identifier (URI) for a given document. ```haskell getDocUri :: TextDocumentIdentifier -> Session URI ``` -------------------------------- ### Get Virtual File Text Content Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Retrieves the text content of a VirtualFile. The content is returned as a Rope. ```haskell virtualFileText :: VirtualFile -> Rope ``` -------------------------------- ### Prepare Virtual File for Disk Persistence Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Determines if a virtual file can be written to disk and returns the file path and an IO action for writing. Requires a logger, target directory, the VFS, and the file's URI. ```haskell persistFileVFS :: LogAction (State VFS) (WithSeverity VfsLog) -> FilePath -> VFS -> NormalizedUri -> Maybe (FilePath, IO ()) ``` -------------------------------- ### Handling Test Framework Exceptions (IOException) Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Shows how to catch `IOException` specifically when running test sessions, useful for diagnosing I/O related issues during testing. ```haskell import Control.Exception runSession "hie" caps "." someTest `catch` \(exc :: IOException) -> do putStrLn $ "I/O error: " ++ show exc ``` -------------------------------- ### Retrieving and Displaying File Content Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Demonstrates how to retrieve a virtual file from the VFS and display its text content and LSP version. ```haskell -- Get file content case vfs' ^? vfsMap . ix (toNormalizedUri "file:///test.hs") . _Open of Just vf -> do let text = vf ^. file_text putStrLn $ "File version: " ++ show (vf ^. lsp_version) Nothing -> putStrLn "File not found" ``` -------------------------------- ### Run LSP Test Session with Configuration Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use runSessionWithConfig to run a test session with custom configuration options. This function takes SessionConfig, server executable, client capabilities, workspace root, and the test session. ```haskell runSessionWithConfig :: SessionConfig -> String -> ClientCapabilities -> FilePath -> Session a -> IO a ``` -------------------------------- ### Get Versioned Document Text Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Retrieves the current version of a document's text, including its version number. ```haskell -- Get current version of document versioned <- getVersionedTextDoc doc ``` -------------------------------- ### Get Versioned Document Identifier Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use this function to retrieve a document's identifier along with its current version number. ```haskell getVersionedDoc :: TextDocumentIdentifier -> Session VersionedTextDocumentIdentifier ``` -------------------------------- ### Set Client Configuration Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Sets the complete client configuration to a new object. ```haskell setConfig :: J.Object -> Session () ``` -------------------------------- ### Get All Open Files Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Retrieves all currently open files managed by the server's virtual file system (VFS). ```haskell -- Get all open files vfs <- getVirtualFiles ``` -------------------------------- ### Enable Logging via Environment Variables Source: https://github.com/haskell/lsp/blob/master/lsp-test/README.md Shows how to enable message and stderr logging for lsp-test from the command line using environment variables. This is helpful for debugging server behavior. ```shell LSP_TEST_LOG_MESSAGES=1 LSP_TEST_LOG_STDERR=1 cabal test ``` -------------------------------- ### Get Virtual File Content Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Retrieves the content of a virtual file from the server's virtual file system (VFS). ```haskell -- Open a file from VFS vf <- getVirtualFile (toNormalizedUri "file:///path/to/file.hs") ``` -------------------------------- ### withWebsocket Function Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Sets up a WebSocket server and runs the LSP server over WebSocket connections. It provides continuation functions for handling incoming and outgoing messages. ```APIDOC ## withWebsocket ### Description Set up WebSocket server and run LSP server over WebSocket connections. ### Parameters - `LogAction IO (WithSeverity LspServerLog)` - Logger - `WebsocketConfig` - WebSocket server config - Continuation receiving input/output functions ### Returns `IO ()` — Blocks until shutdown ``` -------------------------------- ### Get PublishDiagnosticsParams Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/diagnostics.md Retrieves the `PublishDiagnosticsParams` for a given document URI and diagnostic store. Limits the number of diagnostics sent to the client. ```haskell case getDiagnosticParamsFor 1000 store uri of Just params -> sendNotification SMethod_TextDocumentPublishDiagnostics params Nothing -> pure () -- No diagnostics for this URI ``` -------------------------------- ### Recommended Type Import Pattern for LSP Server Source: https://github.com/haskell/lsp/blob/master/_autodocs/modules.md This import pattern is recommended for setting up a complete LSP server. It includes core server modules, protocol types, and testing utilities. ```haskell -- Core server import Language.LSP.Server import Language.LSP.Server.Control -- Types import Language.LSP.Protocol.Types import Language.LSP.Protocol.Message import Language.LSP.Protocol.Capabilities -- Testing import Language.LSP.Test import Language.LSP.Test.Parsing -- Common utilities import Control.Lens import Data.Aeson import Data.Text (Text) ``` -------------------------------- ### Run LSP Server with Custom Handles Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Utilize `runServerWithHandles` to execute an LSP server with specific input and output handles. This is useful when you need to direct server I/O to non-standard streams. ```haskell runServerWithHandles :: LogAction IO (WithSeverity LspServerLog) -> LogAction (LspM config) (WithSeverity LspServerLog) -> Handle -> Handle -> ServerDefinition config -> IO Int ``` ```haskell runServerWithHandles defaultIOLogger defaultLspLogger stdin stdout serverDef ``` -------------------------------- ### Create and Open New Document Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use this function to create a new document with initial content and open it in the editor. It returns a handle to the newly created document. ```haskell createDoc :: FilePath -> String -> Text -> Session TextDocumentIdentifier ``` -------------------------------- ### Logging Errors with Colog Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Example of creating a `LogAction` to specifically log messages with 'Error' or 'Warning' severity using the Colog library. ```haskell import Colog.Core let logger = LogAction $ \(WithSeverity msg severity) -> case severity of Error -> putStrLn $ "ERROR: " ++ msg Warning -> putStrLn $ "WARNING: " ++ msg _ -> pure () ``` -------------------------------- ### Create Range from Line/Character Pairs Source: https://github.com/haskell/lsp/blob/master/_autodocs/types.md Helper function to construct a `Range` object using start and end line and character values. ```haskell mkRange :: UInt -> UInt -> UInt -> UInt -> Range ``` -------------------------------- ### Conditionally Registering Handlers based on Client Capabilities Source: https://github.com/haskell/lsp/blob/master/_autodocs/configuration.md Demonstrates how to dynamically register LSP handlers (e.g., hover, completion) based on the capabilities reported by the client. ```haskell staticHandlers :: ClientCapabilities -> Handlers (LspM Config) staticHandlers caps = mconcat [ if supportsHover caps then requestHandler SMethod_TextDocumentHover hoverHandler else mempty , if supportsCompletion caps then requestHandler SMethod_TextDocumentCompletion completionHandler else mempty ] supportsHover :: ClientCapabilities -> Bool supportsHover caps = case caps ^? textDocument . _Just . hover . _Just . _1 of Just True -> True _ -> False ``` -------------------------------- ### Import Parsing Utilities Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Import the necessary module for using parser combinators to receive messages from the LSP server. ```haskell import Language.LSP.Test.Parsing ``` -------------------------------- ### Get Versioned Text Document Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Annotate a `TextDocumentIdentifier` with the latest version information from the VFS. This ensures you are working with the most up-to-date version of a document. ```haskell getVersionedTextDoc :: MonadLsp config m => TextDocumentIdentifier -> m VersionedTextDocumentIdentifier ``` -------------------------------- ### Applying Content Changes to a File Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Shows how to apply a content change to a virtual file using `changeFromClientVFS`, specifying the range and new text. ```haskell -- Apply changes let change = TextDocumentContentChangeEvent Nothing (Just (Range (Position 0 6) (Position 0 6))) "modified " let vfs'' = changeFromClientVFS logger uri 1 [change] vfs' ``` -------------------------------- ### Get Virtual File Language Kind Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Determines the language identifier for an open virtual file. Returns Nothing if the language cannot be determined. ```haskell virtualFileLanguageKind :: VirtualFile -> Maybe LanguageKind ``` -------------------------------- ### persistFileVFS Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Prepares a virtual file to be written to disk. It returns the file path and an IO action to perform the write operation if successful. ```APIDOC ## persistFileVFS ### Description Prepare to write a virtual file to disk. ### Parameters - **LogAction (State VFS) (WithSeverity VfsLog)** — Logger - **FilePath** — Directory to write to - **VFS** — Current VFS - **NormalizedUri** — File to persist ### Returns `Maybe (FilePath, IO ())` — Path and write action if successful ``` -------------------------------- ### Run LSP Server with Standard I/O Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Use `runServer` for a convenience function that runs an LSP server using standard input, output, and logging. It handles reading from stdin, writing to stdout, logging to stderr and client, and applies default filtering. ```haskell runServer :: forall config. ServerDefinition config -> IO Int ``` ```haskell main :: IO () main = do exitCode <- runServer $ ServerDefinition { defaultConfig = () , configSection = "myserver" , parseConfig = const $ const $ Right () , onConfigChange = const $ pure () , doInitialize = \env _req -> pure $ Right () , staticHandlers = \_ -> handlers , interpretHandler = \() -> Iso id id , options = defaultOptions } exitWith (ExitFailure exitCode) ``` -------------------------------- ### runSessionWithHandles' Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Similar to `runSessionWithHandles`, this function allows running an LSP test session with pre-opened handles, additionally accepting a custom path for log files. ```APIDOC ## runSessionWithHandles' ### Description Run a session with handles and custom log file path. ### Method N/A (Function Signature) ### Endpoint N/A (Function Signature) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example N/A ### Response #### Success Response (200) N/A (Function Returns IO a) #### Response Example N/A ``` -------------------------------- ### runSessionWithConfig Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Runs an LSP test session with custom configuration options. This allows for more control over aspects like message logging and timeouts. ```APIDOC ## runSessionWithConfig ### Description Run a session with custom configuration. ### Method N/A (Function Signature) ### Endpoint N/A (Function Signature) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example N/A ### Response #### Success Response (200) N/A (Function Returns IO a) #### Response Example N/A ``` -------------------------------- ### Bad Practice: Unhandled Handler Exceptions Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Shows an example where exceptions thrown by `handlerLogic` are not caught, leading to unhandled exceptions and potential server crashes. ```haskell -- ✗ Bad - exception propagates requestHandler method $ \req responder -> do r <- handlerLogic -- May throw responder (Right r) ``` -------------------------------- ### Run LSP Test Session with Handles Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md Use runSessionWithHandles to run a test session when you have pre-opened handles to the server's input and output. This is useful for scenarios where the server is managed externally. ```haskell runSessionWithHandles :: ClientCapabilities -> FilePath -> Handle -> Handle -> Session a -> IO a ``` -------------------------------- ### Get Workspace Root Path Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Retrieve the root path of the workspace as determined during server initialization. Returns `Nothing` if the root path could not be determined. ```haskell getRootPath :: MonadLsp config m => m (Maybe FilePath) ``` -------------------------------- ### Bad Practice: Strict Configuration Error Handling Source: https://github.com/haskell/lsp/blob/master/_autodocs/errors.md Highlights a too-strict approach to configuration parsing errors that can break the server by returning `Left` on any failure. ```haskell -- ✗ Bad - too strict parseConfig old val = case fromJSON val of Success cfg -> Right cfg Error msg -> Left (T.pack msg) -- Breaks server ``` -------------------------------- ### Get Virtual File Version Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Retrieves the LSP version number for a given virtual file. Use this to check for updates to a file's content. ```haskell virtualFileVersion :: VirtualFile -> Int32 ``` -------------------------------- ### Useful Imports for Haskell LSP Server Source: https://github.com/haskell/lsp/blob/master/_autodocs/quick-start.md Lists essential imports for building a Haskell LSP server, including core server functionalities, protocol types, and testing utilities. ```haskell -- Core server import Language.LSP.Server -- Types import Language.LSP.Protocol.Types import Language.LSP.Protocol.Message import Language.LSP.Protocol.Capabilities -- Testing import Language.LSP.Test -- Utilities import Control.Lens import Data.Text (Text) import Data.Aeson (fromJSON, toJSON) ``` -------------------------------- ### runServerWithHandles Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Run an LSP server with custom input and output handles. This function allows for explicit control over the input and output streams used by the server. ```APIDOC ## runServerWithHandles ### Description Run a server with custom input and output handles. This function allows for explicit control over the input and output streams used by the server. ### Method ```haskell runServerWithHandles :: LogAction IO (WithSeverity LspServerLog) -> LogAction (LspM config) (WithSeverity LspServerLog) -> Handle -> Handle -> ServerDefinition config -> IO Int ``` ### Parameters - `LogAction IO (WithSeverity LspServerLog)` - Logger for pre-initialization messages - `LogAction (LspM config) (WithSeverity LspServerLog)` - Logger for post-initialization messages - `Handle` - Input handle (reading client messages) - `Handle` - Output handle (writing server responses) - `ServerDefinition config` - Server configuration ### Returns - `IO Int` - Exit code ### Example ```haskell runServerWithHandles defaultIOLogger defaultLspLogger stdin stdout serverDef ``` ``` -------------------------------- ### Get Virtual File by URI Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-core.md Retrieve a virtual file from the Virtual File System (VFS) using its normalized URI. Returns `Nothing` if the file is not open. ```haskell getVirtualFile :: MonadLsp config m => NormalizedUri -> m (Maybe VirtualFile) ``` -------------------------------- ### Run LSP Test Session with Handles and Log Path Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/lsp-test.md runSessionWithHandles' extends runSessionWithHandles by allowing a custom log file path to be specified for session logging. ```haskell runSessionWithHandles' :: ClientCapabilities -> FilePath -> Handle -> Handle -> FilePath -> Session a -> IO a ``` -------------------------------- ### Get Closed Virtual File Language Kind Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/vfs.md Retrieves the language identifier for a closed virtual file. Useful for inspecting files not currently open in the editor. ```haskell closedVirtualFileLanguageKind :: ClosedVirtualFile -> Maybe LanguageKind ``` -------------------------------- ### Apply TextEdit Helper Source: https://github.com/haskell/lsp/blob/master/lsp-types/ChangeLog.md Helper function to apply a TextEdit. ```haskell applyTextEdit :: TextEdit -> Text -> Text ``` -------------------------------- ### Run LSP Server with Custom I/O Functions Source: https://github.com/haskell/lsp/blob/master/_autodocs/api-reference/server-control.md Employ `runServerWith` to run an LSP server using custom functions for reading input and writing output. This provides flexibility for integrating with various I/O mechanisms. ```haskell runServerWith :: LogAction IO (WithSeverity LspServerLog) -> LogAction (LspM config) (WithSeverity LspServerLog) -> IO BS.StrictByteString -> (BSL.LazyByteString -> IO ()) -> ServerDefinition config -> IO Int ```