### Implement Custom Server Resource Handler (Python) Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Demonstrates how to implement a custom server resource handler by extending `ServerResourceInterface`. This is useful when the default NPM or pip handlers are insufficient. It requires defining methods for checking installation status, performing installation/updates, getting the server status, and providing the binary path. ```python from lsp_utils import ServerResourceInterface, ServerStatus, GenericClientHandler from pathlib import Path class CustomServerResource(ServerResourceInterface): def __init__(self, storage_path: str, package_name: str): self._status = ServerStatus.UNINITIALIZED self._storage = Path(storage_path) / package_name self._binary = self._storage / "bin" / "server" def needs_installation(self) -> bool: """Return True if server needs to be installed or updated.""" if not self._binary.exists(): return True # Check version, hash, or other criteria self._status = ServerStatus.READY return False def install_or_update(self) -> None: """Perform the actual installation. Called in background thread.""" try: self._storage.mkdir(parents=True, exist_ok=True) # Download and install server binary # ... self._status = ServerStatus.READY except Exception as e: self._status = ServerStatus.ERROR raise Exception(f"Installation failed: {e}") def get_status(self) -> int: """Return current ServerStatus value.""" return self._status @property def binary_path(self) -> str: """Return filesystem path to server binary.""" return str(self._binary) class LspCustomServerPlugin(GenericClientHandler): package_name = __package__ __server: CustomServerResource | None = None @classmethod def manages_server(cls) -> bool: return True @classmethod def get_server(cls) -> ServerResourceInterface | None: if not cls.__server: cls.__server = CustomServerResource(cls.storage_path(), cls.package_name) return cls.__server ``` -------------------------------- ### Manage Node.js Runtime with NpmClientHandler Source: https://context7.com/sublimelsp/lsp_utils/llms.txt This snippet demonstrates how to get and utilize a Node.js runtime, typically managed by NpmClientHandler. It shows how to retrieve paths to Node.js and npm binaries, get the Node.js version, and execute npm install or run Node.js scripts with custom arguments and environment variables. ```python from lsp_utils import NodeRuntime # Get or resolve Node.js runtime (typically handled by NpmClientHandler) node_runtime = NodeRuntime.get( package_name="LSP-typescript", storage_path="/path/to/storage", required_node_version=">=16" # NPM semver syntax ) if node_runtime: # Get paths to Node.js binaries node_bin = node_runtime.node_bin() # Path to node binary npm_bin = node_runtime.npm_bin() # Path to npm binary # Get Node.js version version = node_runtime.resolve_version() # Returns Version object print(f"Using Node.js {version}") # Run npm install in a directory node_runtime.run_install(cwd="/path/to/server") # Run node with custom arguments process = node_runtime.run_node( args=["script.js", "--arg1"], env={"CUSTOM_VAR": "value"} ) stdout, stderr = process.communicate() ``` -------------------------------- ### Install semantic_version using pip Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This command installs the semantic_version library from the Python Package Index (PyPI). It's the standard way to get the latest stable release of the package. ```sh pip install semantic-version ``` -------------------------------- ### Manage Python Virtual Environments with PipVenvManager Source: https://context7.com/sublimelsp/lsp_utils/llms.txt This snippet illustrates how to use PipVenvManager to manage Python virtual environments for pip-based servers. It covers creating a PipVenvManager instance, checking if installation or an update is needed, performing the installation, and accessing the paths to the virtual environment and its binaries. ```python from lsp_utils import PipVenvManager from pathlib import Path # Create venv manager venv_manager = PipVenvManager( venv_path=Path("/path/to/storage/LSP-python"), requirements_path="LSP-python/requirements.txt", # Relative to Packages/ python_binary="python3" ) # Check if installation is needed if venv_manager.needs_install_or_update(): venv_manager.install() # Access venv paths venv_path = venv_manager.venv_path # /path/to/storage/LSP-python bin_path = venv_manager.venv_bin_path # .../bin (Linux/Mac) or .../Scripts (Windows) ``` -------------------------------- ### NPM Version Specification Examples Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst Demonstrates the usage of the NpmSpec class for validating versions against NPM's range specification scheme. It shows how to check if a given version falls within a specified range or set of ranges. ```pycon >>> Version('0.1.2') in NpmSpec('0.1.0-alpha.2 .. 0.2.4') True >>> Version('0.1.2') in NpmSpec('>=0.1.1 <0.1.3 || 2.x') True >>> Version('2.3.4') in NpmSpec('>=0.1.1 <0.1.3 || 2.x') True ``` -------------------------------- ### Create and inspect a Version object in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This example demonstrates how to create a Version object from a string and access its major, minor, patch, prerelease, and build components. It also shows how to convert the version object back into a list. ```python >>> import semantic_version >>> v = semantic_version.Version('0.1.1') >>> v.major 0 >>> v.minor 1 >>> v.patch 1 >>> v.prerelease [] >>> v.build [] >>> list(v) [0, 1, 1, [], []] ``` -------------------------------- ### Compare Version objects in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This example demonstrates that Version objects can be compared using standard comparison operators (<, >, <=, >=). Comparisons follow the SemVer specification rules. ```python >>> semantic_version.Version('0.1.1') < semantic_version.Version('0.1.2') True >>> semantic_version.Version('0.1.1') > semantic_version.Version('0.1.1-alpha') True >>> semantic_version.Version('0.1.1') <= semantic_version.Version('0.1.1-alpha') False ``` -------------------------------- ### Understand Server Status Enum (Python) Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Defines the `ServerStatus` enumeration used for tracking the installation state of a server. The available status values indicate whether the server is uninitialized, has encountered an error during installation, or is ready for use. ```python from lsp_utils import ServerStatus # Available status values: # ServerStatus.UNINITIALIZED # Initial state, server not yet checked # ServerStatus.ERROR # Installation or update failed # ServerStatus.READY # Server is installed and ready to use ``` -------------------------------- ### NpmClientHandler: NPM-based LSP Client Handler with Node.js Management Source: https://context7.com/sublimelsp/lsp_utils/llms.txt The NpmClientHandler is designed for NPM-based language servers, featuring automatic Node.js management and server installation. It simplifies integration by handling Node.js version checks and dependency installation. Developers can specify server paths, required Node.js versions, and custom variables. ```python from lsp_utils import NpmClientHandler class LspTypeScriptPlugin(NpmClientHandler): package_name = __package__ # Path to server source directory relative to package root server_directory = "language-server" # Path to server binary relative to package storage server_binary_path = "language-server/node_modules/.bin/typescript-language-server" # Skip npm install if server has no dependencies skip_npm_install = False @classmethod def required_node_version(cls) -> str: """Specify required Node.js version using NPM semver syntax.""" return ">=16" # Accepts: "16.x", "16 - 18", ">=16", "16.1.1" @classmethod def get_binary_arguments(cls) -> list[str]: """Default returns ['--stdio']. Override to customize.""" return ["--stdio", "--log-level", "verbose"] @classmethod def get_additional_variables(cls) -> dict[str, str]: """Add variables for use in settings. Includes ${node_bin} and ${server_directory_path}.""" variables = super().get_additional_variables() variables["custom_var"] = "/path/to/custom" return variables def plugin_loaded() -> None: LspTypeScriptPlugin.setup() def plugin_unloaded() -> None: LspTypeScriptPlugin.cleanup() ``` -------------------------------- ### Create Version object using named components in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This example shows how to create a Version object by explicitly providing the major, minor, and patch components as integers. Prerelease and build components can also be provided as tuples of strings. ```python >>> semantic_version.Version(major=0, minor=1, patch=2) Version('0.1.2') >>> semantic_version.Version(major=0, minor=1, patch=2, prerelease=('alpha', '2')) Version('0.1.2-alpha.2') ``` -------------------------------- ### Handle invalid version strings with ValueError in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This example shows that attempting to create a Version object with an invalid string format will raise a ValueError. The library strictly enforces the SemVer specification. ```python >>> semantic_version.Version('0.1') Traceback (most recent call last): File "", line 1, in File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 64, in __init__ major, minor, patch, prerelease, build = self.parse(version_string, partial) File "/Users/rbarrois/dev/semantic_version/src/semantic_version/base.py", line 86, in parse raise ValueError('Invalid version string: %r' % version_string) ValueError: Invalid version string: '0.1' ``` -------------------------------- ### Increment version levels using next_major, next_minor, next_patch in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This example shows how to create a new Version object by incrementing the major, minor, or patch level of an existing version. Build metadata is typically discarded when bumping levels. ```python >>> v = semantic_version.Version('0.1.1+build') >>> new_v = v.next_major() >>> str(new_v) '1.0.0' >>> v = semantic_version.Version('1.1.1+build') >>> new_v = v.next_minor() >>> str(new_v) '1.2.0' >>> v = semantic_version.Version('1.1.1+build') >>> new_v = v.next_patch() >>> str(new_v) '1.1.2' ``` -------------------------------- ### SimpleSpec Version Matching Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst Illustrates the basic usage of the SimpleSpec class for version comparison. It shows how to create a specification (e.g., greater than or equal to a version) and match it against a Version object, noting that pre-release versions do not satisfy the spec. ```pycon >>> s = SimpleSpec('>=0.1.1') # At least 0.1.1 >>> s.match(Version('0.1.1')) True >>> s.match(Version('0.1.1-alpha1')) # pre-release doesn't satisfy version spec False >>> s.match(Version('0.1.0')) False ``` -------------------------------- ### Python LSP API Handler Registration and Communication Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Demonstrates using the GenericClientHandler to establish bidirectional LSP communication. It shows how to register notification and request handlers, send notifications, and send requests with callbacks. Requires the lsp_utils library. ```python from lsp_utils import GenericClientHandler from typing import Any, Callable class LspCustomPlugin(GenericClientHandler): package_name = __package__ def on_ready(self, api) -> None: # Register notification handler api.on_notification("custom/statusUpdate", self.handle_status) # Register request handler (server sends request, client responds) api.on_request("custom/getConfig", self.handle_config_request) # Send notification to server api.send_notification("custom/clientReady", {"version": "1.0.0"}) # Send request to server with callback api.send_request( "custom/getServerInfo", {"include_version": True}, self.handle_server_info_response ) def handle_status(self, params: Any) -> None: """Handle notification from server.""" print(f"Server status: {params.get('status')}") def handle_config_request(self, params: Any, respond: Callable[[Any], None]) -> None: """Handle request from server and send response.""" config = {"setting1": True, "setting2": "value"} respond(config) # Must call respond() to send response back def handle_server_info_response(self, result: Any, is_error: bool) -> None: """Handle response from server request.""" if is_error: print(f"Request failed: {result}") else: print(f"Server info: {result}") ``` -------------------------------- ### SimpleSpec Equality and Build Variants Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst Explains how to use the 'in' keyword with SimpleSpec for simpler version testing, specifically for exact matches (==). It highlights that build variants are considered equivalent to full versions, but pre-release variants do not match. ```pycon >>> s = SimpleSpec('==0.1.1') >>> Version('0.1.1+git7ccc72') in s # build variants are equivalent to full versions True >>> Version('0.1.1-alpha1') in s # pre-release variants don't match the full version. False >>> Version('0.1.2') in s False ``` -------------------------------- ### Execute Shell Commands (Python) Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Provides utility functions for executing shell commands synchronously and asynchronously. `run_command_sync` offers full control over execution, `run_command_async` uses callbacks for handling output, and `run_command_ex` is a simpler synchronous version that raises exceptions on errors. ```python from lsp_utils.helpers import run_command_sync, run_command_async, run_command_ex # Synchronous execution with full control output, error = run_command_sync( args=["node", "--version"], cwd="/path/to/project", extra_env={"NODE_ENV": "production"}, extra_paths=["/usr/local/bin"], shell=False ) if error: print(f"Command failed: {error}") else: print(f"Node version: {output}") # Async execution with callbacks def on_success(output: str) -> None: print(f"Success: {output}") def on_error(error: str) -> None: print(f"Error: {error}") run_command_async( args=["npm", "install"], on_success=on_success, on_error=on_error, cwd="/path/to/project" ) # Simple synchronous execution that raises on error try: version = run_command_ex("python3", "--version") print(f"Python: {version}") except Exception as e: print(f"Failed: {e}") ``` -------------------------------- ### Handle Semantic Versions (Python) Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Provides a helper function `version_to_string` for converting semantic version tuples into their standard string representation. It uses the `SemanticVersion` type hint for clarity. ```python from lsp_utils.helpers import version_to_string, SemanticVersion # Convert version tuple to string version: SemanticVersion = (16, 14, 2) version_str = version_to_string(version) # Returns "16.14.2" ``` -------------------------------- ### Python LSP Decorator Handlers for Notifications and Requests Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Illustrates using decorators like @notification_handler and @request_handler for automatic registration of LSP message handlers. This simplifies handler management compared to manual registration. Requires lsp_utils and standard Python libraries. ```python from lsp_utils import GenericClientHandler, notification_handler, request_handler from typing import Any, Callable import webbrowser class LspEslintPlugin(GenericClientHandler): package_name = __package__ @notification_handler("eslint/status") def handle_eslint_status(self, params: Any) -> None: """Automatically registered to handle 'eslint/status' notifications.""" state = params.get("state") print(f"ESLint status: {state}") @notification_handler(["eslint/noLibrary", "eslint/noConfig"]) def handle_eslint_errors(self, params: Any) -> None: """Handle multiple notification types with single handler.""" print(f"ESLint configuration issue: {params}") @request_handler("eslint/openDoc") def handle_open_doc(self, params: Any, respond: Callable[[Any], None]) -> None: """Handle server request to open documentation.""" url = params.get("url") if url: webbrowser.open(url) respond({}) @request_handler("eslint/confirmAction") def handle_confirm(self, params: Any, respond: Callable[[Any], None]) -> None: """Handle confirmation request from server.""" import sublime action = params.get("action", "proceed") confirmed = sublime.ok_cancel_dialog(f"ESLint: Confirm {action}?") respond({"confirmed": confirmed}) ``` -------------------------------- ### Perform File Operations (Python) Source: https://context7.com/sublimelsp/lsp_utils/llms.txt Offers utility functions for common file operations such as downloading files from URLs, extracting various archive formats (zip, tar.gz, etc.), and robust directory tree removal. `rmtree_ex` is designed to handle potential issues like Windows long paths. ```python from lsp_utils import download_file, extract_archive, rmtree_ex from pathlib import Path # Download a file from URL cache_dir = Path("/path/to/cache") archive_path = cache_dir / "server.tar.gz" download_file("https://example.com/server.tar.gz", archive_path) # Extract archive (supports .zip, .tar.gz, .tgz, .tar.bz2, .tar.xz) # Returns path to extracted directory extracted_dir = extract_archive(archive_path, Path("/path/to/install")) print(f"Extracted to: {extracted_dir}") # Remove directory tree (handles Windows long paths) rmtree_ex("/path/to/old/installation", ignore_errors=True) ``` -------------------------------- ### SimpleSpec Selecting Best Version Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst Shows how to use the SimpleSpec.select method to find the 'best' matching version from an iterable of Version objects according to the specification. This is useful for identifying the highest compliant version. ```pycon >>> s = SimpleSpec('>=0.1.0,<0.4.0') >>> versions = (Version('0.%d.0' % i) for i in range(6)) >>> s.select(versions) Version('0.3.0') ``` -------------------------------- ### PipClientHandler: Pip-based LSP Client Handler with Virtual Environment Management Source: https://context7.com/sublimelsp/lsp_utils/llms.txt The PipClientHandler facilitates integration of pip-based Python language servers by managing virtual environments. It automatically handles the creation and management of virtual environments for the language server. Developers need to specify the path to requirements.txt and the server's binary filename. ```python from lsp_utils.pip_client_handler import PipClientHandler class LspPythonPlugin(PipClientHandler): package_name = __package__ # Path to requirements.txt relative to package root requirements_txt_path = "requirements.txt" # Binary filename in venv bin directory (without extension) server_filename = "pylsp" @classmethod def get_python_binary(cls) -> str: """Return Python binary name or path for creating the venv.""" import sublime if sublime.platform() == "windows": return "py" # or "python" return "python3" @classmethod def get_additional_paths(cls) -> list[str]: """Prepend paths to PATH env variable.""" paths = super().get_additional_paths() # Server binary directory is automatically added return paths def plugin_loaded() -> None: LspPythonPlugin.setup() def plugin_unloaded() -> None: LspPythonPlugin.cleanup() ``` -------------------------------- ### GenericClientHandler: Basic LSP Client Handler for Sublime Text Source: https://context7.com/sublimelsp/lsp_utils/llms.txt The GenericClientHandler is a base class for creating LSP plugin handlers in Sublime Text. It provides core functionality for server management, settings handling, and LSP integration. Developers can override methods like get_displayed_name, get_command, and on_ready to customize server behavior. ```python from lsp_utils import GenericClientHandler class LspMyLanguagePlugin(GenericClientHandler): package_name = __package__ # Required: matches your .sublime-settings filename @classmethod def get_displayed_name(cls) -> str: """Override to customize the name shown in Sublime Text UI.""" return "My Language Server" @classmethod def get_command(cls) -> list[str]: """Return the command to start the language server.""" return ["my-language-server", "--stdio"] @classmethod def get_binary_arguments(cls) -> list[str]: """Return extra arguments for the server binary.""" return ["--log-level", "info"] @classmethod def is_allowed_to_start(cls, window, initiating_view, workspace_folders, configuration) -> str | None: """Return None to allow starting, or a string with reason to prevent.""" if not workspace_folders: return "No workspace folder found" return None def on_ready(self, api) -> None: """Called when the server session is ready.""" print(f"{self.package_name} server is ready!") def on_settings_changed(self, settings) -> None: """Called when settings change, allowing modification before sending to server.""" settings.set("custom_option", True) def plugin_loaded() -> None: LspMyLanguagePlugin.setup() def plugin_unloaded() -> None: LspMyLanguagePlugin.cleanup() ``` -------------------------------- ### Clone semantic_version from GitHub Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This command clones the semantic_version library directly from its GitHub repository. This is useful for development or for obtaining the absolute latest code, which may not yet be released on PyPI. ```sh git clone git://github.com/rbarrois/python-semanticversion.git ``` -------------------------------- ### Define Package Control Dependencies (JSON) Source: https://github.com/sublimelsp/lsp_utils/blob/main/README.md Specifies the 'lsp_utils' and 'sublime_lib' packages as dependencies for Package Control. This configuration is placed in a `dependencies.json` file within the package root. ```json { "*": { "*": [ "lsp_utils", "sublime_lib" ] } } ``` -------------------------------- ### Import the semantic_version library in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst This Python code snippet shows how to import the entire semantic_version library. Once imported, you can access its classes and functions, such as Version and SimpleSpec. ```python import semantic_version ``` -------------------------------- ### SimpleSpec Filtering Iterable of Versions Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst Demonstrates the use of the SimpleSpec.filter method to filter an iterable of Version objects based on a given specification. It shows how to obtain a subset of versions that satisfy the criteria. ```pycon >>> s = SimpleSpec('>=0.1.0,<0.4.0') >>> versions = (Version('0.%d.0' % i) for i in range(6)) >>> for v in s.filter(versions): ... print v 0.1.0 0.2.0 0.3.0 ``` -------------------------------- ### Coerce version-like strings to valid SemVer in Python Source: https://github.com/sublimelsp/lsp_utils/blob/main/lsp_utils/third_party/semantic_version/README.rst The Version.coerce method attempts to convert various version-like strings into a valid semantic version format. This is useful for handling less strict input. ```python >>> Version.coerce('0') Version('0.0.0') >>> Version.coerce('0.1.2.3.4') Version('0.1.2+3.4') >>> Version.coerce('0.1.2a3') Version('0.1.2-a3') ``` -------------------------------- ### Handle LSP Requests with @request_handler Source: https://github.com/sublimelsp/lsp_utils/blob/main/docs/source/api_handler.rst The @request_handler decorator is used to handle incoming LSP requests. It accepts the request name and optionally a list of names. The decorated function receives request parameters and a 'respond' callback to send a response back to the client. This is an alternative to ApiWrapperInterface listeners. ```python import webbrowser from typing import Any, Callable @request_handler('eslint/openDoc') def handle_open_doc(self, params: Any, respond: Callable[[Any], None]) -> None: webbrowser.open(params['url']) respond({}) ``` -------------------------------- ### Handle LSP Notifications with @notification_handler Source: https://github.com/sublimelsp/lsp_utils/blob/main/docs/source/api_handler.rst The @notification_handler decorator allows you to register a function to handle specific LSP notifications. It takes the notification name as an argument. This method is an alternative to using ApiWrapperInterface listeners. ```python from typing import Any @notification_handler('eslint/status') def handle_status(self, params: Any) -> None: print(status) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.