### Install Rassumfrassum and Language Servers (Bash) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Installs the rassumfrassum tool and example language servers (ty and ruff) using pip. This is the initial setup step for using the tool. ```bash pip install rassumfrassum ty ruff ``` -------------------------------- ### Running the Rassumfrassum CLI Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Demonstrates how to start the LSP multiplexer using the 'rass' command, including basic server chaining, preset usage, and running from source. ```bash rass -- ty server -- ruff server rass python rass python -- codebook-lsp server rass tslint rass --delay-ms 100 --log-level debug -- basedpyright-langserver -- ruff server export PYTHONPATH=$PWD/src python3 -m rassumfrassum -- ty server -- ruff server ``` -------------------------------- ### Configuring CLI Options Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Examples of configuring multiplexer behavior such as logging levels, response delays, diagnostic streaming, and custom routing logic. ```bash rass --help rass --log-level trace python rass --delay-ms 3000 -- ty server -- ruff server rass --drop-tardy python rass --stream-diagnostics python rass --no-stream-diagnostics python rass --quiet-server python rass --logic-class mymodule.MyCustomLogic -- ty server -- ruff server rass --max-log-length 8000 python ``` -------------------------------- ### Run Rassumfrassum with Specific Servers (Bash) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Demonstrates how to run rassumfrassum by explicitly specifying multiple language servers to connect to, using 'ty server' and 'ruff server' as an example. ```bash rass -- ty server -- ruff server ``` -------------------------------- ### Configure Emacs Eglot for Rassumfrassum Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Methods to integrate Rassumfrassum with Emacs Eglot, including interactive setup and programmatic configuration using eglot-server-programs. ```elisp (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '(python-mode . ("rass" "python")))) (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '(python-mode . ("rass" "--" "basedpyright-langserver" "--stdio" "--" "ruff" "server")))) ``` -------------------------------- ### Implement Server and Client Communication with CommunicationLogic Source: https://context7.com/joaotavora/rassumfrassum/llms.txt The CommunicationLogic class demonstrates how to send requests and notifications to servers and clients using provided callback functions. It includes examples for handling server notifications like 'textDocument/publishDiagnostics' by making requests to and sending notifications to servers, as well as forwarding notifications to the client. It also shows how to handle client requests, such as 'workspace/executeCommand', by requesting configuration from the client. ```python from rassumfrassum.frassum import LspLogic, Server, DirectResponse from rassumfrassum.json import JSON class CommunicationLogic(LspLogic): """Example of server/client communication APIs.""" async def on_server_notification( self, method: str, params: JSON, source: Server ) -> None: """Demonstrate server communication.""" if method == 'textDocument/publishDiagnostics': uri = params.get('uri') # Send request to server and await response is_error, response = await self.request_server( source, 'textDocument/diagnostic', {'textDocument': {'uri': uri}} ) if not is_error: print(f"Pull diagnostics: {response}") # Send notification to server (no response) await self.notify_server( source, 'workspace/didChangeConfiguration', {'settings': {}} ) # Forward notification to client await self.notify_client(method, params) async def on_client_request( self, method: str, params: JSON, servers: list[Server] ): """Demonstrate client communication.""" if method == 'workspace/executeCommand': # Send request to client and await response is_error, config = await self.request_client( 'workspace/configuration', {'items': [{'section': 'myExtension'}]} ) if not is_error: print(f"Got client config: {config}") return await super().on_client_request(method, params, servers) ``` -------------------------------- ### Streaming Diagnostics Protocol Extension Example Source: https://context7.com/joaotavora/rassumfrassum/llms.txt This section illustrates the Rassumfrassum implementation of an experimental protocol extension for incrementally streaming diagnostics. It shows how a client advertises support in its initialize request, how a server confirms this support in its initialize result, and the structure of the '$/streamDiagnostics' notification that replaces 'textDocument/publishDiagnostics' for incremental updates. ```json # Client advertises support in initialize request initialize_params = { "capabilities": { "textDocument": { "$streamingDiagnostics": True, # Enable streaming mode # ... other capabilities } } } # Server responds with streaming support initialize_result = { "capabilities": { "$streamingDiagnosticsProvider": True, # Confirms streaming enabled # ... other capabilities } } # Instead of textDocument/publishDiagnostics, client receives: # $/streamDiagnostics notification for each server's diagnostics stream_notification = { "jsonrpc": "2.0", "method": "$/streamDiagnostics", "params": { "uri": "file:///path/to/file.py", "version": 1, "token": "ruff-140234567890", # Unique per-server identifier "diagnostics": [ { "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 5}}, "message": "Unused import", "severity": 2, "source": "ruff" } ] } } ``` -------------------------------- ### Run Rassumfrassum from Git Checkout (Bash) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Executes rassumfrassum directly from a Git source checkout without installation. It sets the PYTHONPATH environment variable and uses 'python3 -m' to run the module. ```bash export PYTHONPATH=$PWD/src python3 -m rassumfrassum -- ty server -- ruff server ``` -------------------------------- ### Diagnostic Notification Structure Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Example of a JSON-RPC notification for streaming diagnostics. The 'kind' field set to 'unchanged' allows the client to reuse previous diagnostic data for a specific version and URI. ```json unchanged_notification = { "jsonrpc": "2.0", "method": "$/streamDiagnostics", "params": { "uri": "file:///path/to/file.py", "version": 2, "token": "ruff-140234567890", "kind": "unchanged" } } ``` -------------------------------- ### Defining Simple LSP Presets Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Shows how to create reusable preset files in Python that define which language servers should be spawned by the multiplexer. ```python def servers(): return [ ['pylsp'], ['ruff', 'server'] ] def servers(): return [ ['typescript-language-server', '--stdio'], ['biome', 'lsp-proxy'], ] ``` -------------------------------- ### Extend Preset with Additional Server (Bash) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Shows how to use a preset (e.g., 'python') and add another language server (e.g., 'codebook-lsp' for spell checking) using the '--' separator. ```bash rass python -- codebook-lsp server ``` -------------------------------- ### Implement Custom Vue Language Server Logic Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Demonstrates how to create a custom LspLogic class to dynamically discover the TypeScript SDK path and configure initialization options for the Vue language server. ```python import asyncio from pathlib import Path from rassumfrassum.frassum import LspLogic, Server from rassumfrassum.json import JSON from rassumfrassum.util import dmerge class VueLogic(LspLogic): async def on_client_request(self, method: str, params: JSON, servers: list[Server]): if method == 'initialize': try: proc = await asyncio.create_subprocess_exec( 'npm', 'list', '--global', '--parseable', 'typescript', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, _ = await proc.communicate() first_line = stdout.decode().strip().split('\n')[0] tsdk_path = str(Path(first_line) / 'lib') except Exception: tsdk_path = '/usr/local/lib/node_modules/typescript/lib' params['initializationOptions'] = dmerge( params.get('initializationOptions') or {}, {'typescript': {'tsdk': tsdk_path}, 'vue': {'hybridMode': False}}, ) return await super().on_client_request(method, params, servers) ``` -------------------------------- ### Use Bundled Python Preset (Bash) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Executes the bundled 'python' preset for rassumfrassum, which typically includes servers like 'ty' and 'ruff' for Python development. ```bash rass python ``` -------------------------------- ### Manage Rassumfrassum Presets Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Commands and configuration patterns for overriding bundled presets or creating custom language server combinations. ```bash mkdir -p ~/.config/rassumfrassum cat > ~/.config/rassumfrassum/python.py << 'EOF' def servers(): return [ ['basedpyright-langserver', '--stdio'], ['ruff', 'server'], ['codebook-lsp', 'server'], ] EOF rass python ``` -------------------------------- ### Configure Neovim LSP for Rassumfrassum Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Methods to integrate Rassumfrassum with Neovim using the built-in LSP client or the lspconfig plugin for Python and TypeScript. ```lua vim.lsp.config('rass-python', { cmd = {'rass', 'python'}, filetypes = {'python'}, root_markers = {'.git', 'pyproject.toml', 'setup.py'}, }) vim.lsp.enable('rass-python') local lspconfig = require('lspconfig') local configs = require('lspconfig.configs') if not configs.rass_python then configs.rass_python = { default_config = { cmd = {'rass', 'python'}, filetypes = {'python'}, root_dir = lspconfig.util.root_pattern('.git', 'pyproject.toml'), settings = {}, }, } end ``` -------------------------------- ### Route LSP Client Requests Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Shows how to override on_client_request to implement custom routing logic, such as filtering servers by capability or returning direct responses. ```python from rassumfrassum.frassum import LspLogic, Server, DirectResponse from rassumfrassum.json import JSON class MyLogic(LspLogic): async def on_client_request(self, method: str, params: JSON, servers: list[Server]) -> list[Server] | DirectResponse: if method == 'textDocument/codeAction': return [s for s in servers if s.caps.get('codeActionProvider')] if method == 'textDocument/formatting': for s in servers: if s.caps.get('documentFormattingProvider'): return [s] return [] if method == 'custom/cachedData': cached = self.get_cached_response(params) if cached: return DirectResponse(payload=cached) return [servers[0]] if servers else [] ``` -------------------------------- ### Configure Neovim for Rassumfrassum (Lua) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Configures the built-in LSP client in Neovim to use rassumfrassum for Python development. It defines the command to run, filetypes, and root markers. ```lua vim.lsp.config('rass-python', { cmd = {'rass','python'}, filetypes = { 'python' }, root_markers = { '.git', }, }) vim.lsp.enable('rass-python') ``` -------------------------------- ### Handle LSP Notifications Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Illustrates how to intercept and process client-to-server and server-to-client notifications for tasks like logging or diagnostic monitoring. ```python from rassumfrassum.frassum import LspLogic, Server from rassumfrassum.json import JSON class NotificationLogic(LspLogic): async def on_client_notification(self, method: str, params: JSON) -> None: if method == 'textDocument/didOpen': uri = params["textDocument"]["uri"] print(f"Document opened: {uri}") for server in self.servers.values(): await self.notify_server(server, method, params) async def on_server_notification(self, method: str, params: JSON, source: Server) -> None: if method == 'textDocument/publishDiagnostics': print(f"Diagnostics from {source.name}") await self.notify_client(method, params) ``` -------------------------------- ### LspLogic Class - Client Request Routing Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Demonstrates custom routing logic for client requests within the LspLogic class, allowing specific requests to be directed to certain servers or to return immediate responses. ```APIDOC ## LspLogic Class - Client Request Routing ### Description The `LspLogic` class provides a mechanism to customize how client requests are routed to available Language Server Protocol (LSP) servers. This includes selectively forwarding requests based on server capabilities, routing to a primary server, or intercepting requests to provide a direct response without forwarding. ### Method `on_client_request(self, method: str, params: JSON, servers: list[Server]) -> list[Server] | DirectResponse` ### Endpoint N/A (Internal method) ### Parameters - **method** (str) - The LSP request method being called. - **params** (JSON) - The parameters associated with the request. - **servers** (list[Server]) - A list of available LSP servers. ### Request Example N/A (This method handles incoming requests) ### Response - `list[Server]` - A list of servers to which the request should be forwarded. - `DirectResponse` - An object containing a `payload` for an immediate response, bypassing server forwarding. ### Response Example ```json { "payload": { "some": "data" } } ``` ### Code Example ```python from rassumfrassum.frassum import LspLogic, Server, DirectResponse from rassumfrassum.json import JSON class MyLogic(LspLogic): """Custom routing logic example.""" async def on_client_request( self, method: str, params: JSON, servers: list[Server] ) -> list[Server] | DirectResponse: """ Route client requests to appropriate servers. Returns: list[Server]: Servers that should receive the request DirectResponse: Immediate response without forwarding """ # Route to all servers that support the capability if method == 'textDocument/codeAction': return [s for s in servers if s.caps.get('codeActionProvider')] # Route to first server with capability if method == 'textDocument/formatting': for s in servers: if s.caps.get('documentFormattingProvider'): return [s] return [] # Return immediate response without forwarding if method == 'custom/cachedData': cached = self.get_cached_response(params) if cached: return DirectResponse(payload=cached) # Default: route to primary server only return [servers[0]] if servers else [] ``` ``` -------------------------------- ### Custom Python Preset for Rassumfrassum (Python) Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Defines a custom Python preset named 'pylspruff' in a user configuration file. It specifies the 'pylsp' and 'ruff' language servers to be used. ```python """Python preset using pylsp instead of ty.""" def servers(): return [ ['pylsp'], ['ruff', 'server'] ] ``` -------------------------------- ### Vue Preset with TypeScript SDK Discovery Source: https://context7.com/joaotavora/rassumfrassum/llms.txt This preset configures RassumFrassum for Vue development, automatically discovering the TypeScript SDK path for the vue-language-server. ```APIDOC ## Vue Preset Configuration ### Description This configuration customizes the Language Server Protocol (LSP) logic for Vue projects. It specifically handles the initialization of `vue-language-server` by attempting to discover the installed TypeScript SDK path. If `npm list --global --parseable typescript` fails, it falls back to a default path. ### Method N/A (Configuration) ### Endpoint N/A (Configuration) ### Parameters N/A ### Request Example N/A ### Response N/A ### Code Example ```python import asyncio from pathlib import Path from rassumfrassum.frassum import LspLogic, Server from rassumfrassum.json import JSON from rassumfrassum.util import dmerge class VueLogic(LspLogic): """Custom logic for Vue-friendly servers.""" async def on_client_request( self, method: str, params: JSON, servers: list[Server] ): if method == 'initialize': # vue-language-server requires TypeScript SDK path try: proc = await asyncio.create_subprocess_exec( 'npm', 'list', '--global', '--parseable', 'typescript', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, _ = await proc.communicate() first_line = stdout.decode().strip().split('\n')[0] tsdk_path = str(Path(first_line) / 'lib') except Exception: tsdk_path = '/usr/local/lib/node_modules/typescript/lib' params['initializationOptions'] = dmerge( params.get('initializationOptions') or {}, { 'typescript': {'tsdk': tsdk_path}, 'vue': {'hybridMode': False}, }, ) return await super().on_client_request(method, params, servers) def servers(): return [ ['vue-language-server', '--stdio'], ['tailwindcss-language-server', '--stdio'], ] def logic_class(): """Return custom logic class.""" return VueLogic ``` ``` -------------------------------- ### Process Server Responses with AggregationLogic Source: https://context7.com/joaotavora/rassumfrassum/llms.txt The AggregationLogic class in Rassumfrassum processes responses from multiple servers. It aggregates successful responses, handling specific methods like 'textDocument/codeAction' and 'textDocument/definition' by merging results, and defaults to returning the first successful response if no specific aggregation logic applies. Error responses are handled by returning the first encountered error. ```python from rassumfrassum.frassum import LspLogic, PayloadItem from rassumfrassum.json import JSON from typing import cast class AggregationLogic(LspLogic): """Custom response aggregation example.""" def process_responses( self, method: str, items: list[PayloadItem], ) -> tuple[JSON | list, bool]: """ Aggregate multiple server responses. Args: method: LSP method name items: List of PayloadItem(payload, server, is_error) Returns: (aggregated_payload, is_error) """ # Filter out error responses successful = [i for i in items if not i.is_error and i.payload] if not successful: # All errors - return first error return items[0].payload, True # Aggregate code actions by concatenating lists if method == 'textDocument/codeAction': all_actions = [] for item in successful: all_actions.extend(cast(list, item.payload) or []) return all_actions, False # Aggregate definitions by merging location lists if method in ('textDocument/definition', 'textDocument/references'): all_locations = [] for item in successful: payload = item.payload if isinstance(payload, list): all_locations.extend(payload) elif isinstance(payload, dict): all_locations.append(payload) return all_locations, False # Default: return first successful response return successful[0].payload, False ``` -------------------------------- ### LspLogic Class - Notification Handling Source: https://context7.com/joaotavora/rassumfrassum/llms.txt Details the handling of client and server notifications within the LspLogic class, enabling custom processing of events like document changes and diagnostic reports. ```APIDOC ## LspLogic Class - Notification Handling ### Description This section describes how to customize the handling of Language Server Protocol (LSP) notifications using the `LspLogic` class. It covers both notifications sent from the client to servers (`on_client_notification`) and from servers to the client (`on_server_notification`), allowing for custom logging, processing, and forwarding logic. ### Method - `on_client_notification(self, method: str, params: JSON) -> None` - `on_server_notification(self, method: str, params: JSON, source: Server) -> None` ### Endpoint N/A (Internal methods) ### Parameters - **method** (str) - The LSP notification method. - **params** (JSON) - The parameters associated with the notification. - **source** (Server) - The server from which the notification originated (for `on_server_notification`). ### Request Example N/A (These methods handle incoming notifications) ### Response N/A (Notifications are typically one-way) ### Code Example ```python from rassumfrassum.frassum import LspLogic, Server from rassumfrassum.json import JSON class NotificationLogic(LspLogic): """Custom notification handling example.""" async def on_client_notification(self, method: str, params: JSON) -> None: """ Handle notifications from client to servers. Called before forwarding to servers. """ if method == 'textDocument/didOpen': uri = params["textDocument"]["uri"] version = params["textDocument"]["version"] print(f"Document opened: {uri} v{version}") # Forward to all servers by default for server in self.servers.values(): await self.notify_server(server, method, params) async def on_server_notification( self, method: str, params: JSON, source: Server ) -> None: """ Handle notifications from servers to client. Called before forwarding to client. """ if method == 'textDocument/publishDiagnostics': uri = params.get('uri') diags = params.get('diagnostics', []) print(f"Diagnostics from {source.name}: {len(diags)} items for {uri}") # Forward to client await self.notify_client(method, params) ``` ``` -------------------------------- ### Configure Eglot in Emacs for Rassumfrassum Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md Configures the Eglot LSP client in Emacs to use rassumfrassum for Python development. It specifies how to invoke the 'rass' command with the 'python' argument. ```emacs-lisp C-u M-x eglot RET rass python RET ``` -------------------------------- ### NOTIFY $/streamDiagnostics Source: https://github.com/joaotavora/rassumfrassum/blob/master/README.md The $/streamDiagnostics notification is sent from the server to the client to provide incremental diagnostic updates from specific sources. ```APIDOC ## NOTIFY $/streamDiagnostics ### Description This notification is used to stream diagnostics from multiple sources. It allows the client to receive updates incrementally, indexed by a version, URI, and a unique source token. ### Method NOTIFY ### Endpoint $/streamDiagnostics ### Parameters #### Request Body - **uri** (string) - Required - The document URI. - **version** (number) - Required - The document version. - **token** (string) - Required - A unique identifier for the diagnostic source. - **diagnostics** (array) - Optional - The list of diagnostic objects. - **kind** (string) - Optional - Set to "unchanged" if diagnostics for this token have not changed. ### Request Example { "uri": "file:///path/to/file.py", "version": 1, "token": "server-1", "diagnostics": [ { "range": { "start": { "line": 0, "character": 0 }, "end": { "line": 0, "character": 5 } }, "message": "Example diagnostic message" } ] } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.