pygls

repository·main·Indexed 21 days ago

https://github.com/openlawlibrary/pygls

A Pythonic generic framework for implementing the Language Server Protocol (LSP), allowing developers to build custom, editor-agnostic language servers. Version 2.1.1 supports Python 3.9+ on Windows, MacOS, and Linux, with communication via STDIO, TCP/IP, and WEBSOCKET. It provides APIs for servers, clients, and workspace management, utilizing the lsprotocol library for official LSP type definitions.

Tokens
33.6K
Snippets
102
Records
165
Agent score
73%

What's inside pygls

  1. Overview of pygls

    main

    pygls (pronounced "pie glass") is a generic implementation of the Language Server Protocol (LSP) written in Python. It is designed to allow developers to write their own language servers with minimal code.

    Key features include:

    • Support for Python 3.9+ on Windows, MacOS, and Linux.
    • Experimental support for Pyodide.
    • Communication via STDIO, TCP/IP, and WEBSOCKET.
    • Support for both synchronous and asynchronous programming styles.
    • Ability to run code in background threads.
    • Automatic synchronization for text and notebook documents.
  2. Explore the pygls Python API

    main

    The pygls Python API is organized into several functional areas depending on whether you are building a Language Client, a Language Server, or working with low-level protocol details. The API surface includes:

    • Clients: APIs for implementing Language Clients.
    • Servers: APIs for implementing Language Servers.
    • LSP Types: Type definitions provided via the lsprotocol library.
    • URIs: Helper functions for managing and working with URIs.
    • Workspace: APIs for managing the workspace state and files.
    • Protocol: Low-level APIs for interacting directly with the LSP protocol.
    • IO: Low-level input/output APIs.
  3. View implementations and tools based on pygls

    main
    The pygls framework is used by various language servers and developer tools. You can explore existing implementations to see how the framework is applied to different languages (like Python, Chapel, or YARA) or configuration formats (like CMake or Systemd). Additionally, there are developer tools built on pygls to assist in the creation and testing of language servers.
  4. What is pygls and when should I use it?

    main

    pygls (pronounced "pie glass") is a Pythonic generic implementation of the Language Server Protocol (LSP). It serves as a foundation for writing custom Language Servers with minimal boilerplate.

    When to use pygls:

    • When you want to write your Language Server in Python.
    • When you want to support multiple editors (unlike Microsoft's NodeJS-based framework which is heavily focused on VSCode, pygls is editor-agnostic).
    • When you prefer implementing logic through programming rather than complex configuration-based general-purpose servers.
  5. How to interpret Semantic Tokens

    main

    Semantic Tokens provide advanced syntax highlighting (often called "Syntax Highlighting++") by providing semantic context that regular expressions cannot, such as identifying if a variable is read-only, a function is deprecated, or a class belongs to a standard library.

    Unlike most LSP features, semantic tokens are not represented as structured objects with named fields. Instead, they are sent as a flat sequence of integers where every 5 integers represent a single token:

    [line, character, length, type, modifiers, ...]

    Example sequence:

    [0, 2, 1, 0, 3,  0, 4, 2, 1, 0, ...]
     ^-----------^   ^-----------^ 
      1st token       2nd token
  6. Automated release metadata and PyPI pre-releases

    main

    The PyGLS release process includes several automated behaviors:

    • Metadata Automation: The GitHub Release Action automatically populates CHANGELOG.md and CONTRIBUTORS.md.
    • PyPI Pre-release Handling: PyPI automatically detects alpha and beta versions from the version string (e.g., v1.0.0a). These versions are made publicly available but will not be installed by downstream projects using loose version pinning (e.g., ^1.0.0) unless explicitly requested.
  7. Use Semantic Token Modifiers with bit flags

    main

    The 5th integer in the sequence represents Token Modifiers (e.g., marking a token as deprecated or readOnly).

    Because a single token can have multiple modifiers, they are encoded using bit flags rather than a simple list index. To determine which modifiers are active, view the integer as a binary bitmask:

    • A tokenModifier value of 3 is binary 0b00000011.
    • This indicates that both tokenModifiers[0] and tokenModifiers[1] are applied to the token.

    Like types, the available modifiers must be declared by the server in the SemanticTokensLegend sent during the initialize request.

  8. How built-in features and custom handlers interact in pygls

    main

    The LanguageServer class includes many low-level LSP features implemented by default. While you cannot disable these built-in features, you can "shadow" them by registering your own handlers using the @server.feature decorator.

    When you register a custom handler, pygls manages the execution order. The specific timing depends on the feature:

    • Lifecycle features (initialize, shutdown, exit): The order varies. For initialize, your handler runs after workspace initialization but before capability computation. For shutdown and exit, your handler runs before the built-in handler.
    • Synchronization features (textDocument/*, notebookDocument/*, workspace/*): Your custom handler is called after the built-in handler. This ensures that when your code runs, the internal state (like document contents) has already been updated by the built-in logic.
  9. How the pygls converter handles data serialization

    main

    pygls uses the lsprotocol library for type definitions, which relies on attrs and cattres for JSON serialization and deserialization. This process is managed by a converter object.

    By default, pygls uses pygls.protocol.default_converter, which strictly follows the Language Server Protocol. Because it is pedantic, the server will raise a pygls.exceptions.JsonRpcInvalidParams error if it receives data that does not perfectly match the expected types (e.g., a null value where an integer is expected).

    >>> from lsprotocol.types import Position
    >>> from pygls.protocol import default_converter
    
    >>> converter = default_converter()
    >>> p = converter.structure({"line": 1, "character": 2}, Position)
    >>> p.line
    1
    >>> p.character
    2
  10. Understand Semantic Token Position encoding

    main

    The first three integers in a token's 5-integer sequence encode its position in the document:

    1. Line Offset: The line number.
    2. Character Offset: The character position on that line.
    3. Length: The number of characters the token spans.

    CRITICAL: These offsets are relative to the start of the previous token.

    • For the very first token in a document, the position is calculated relative to (0, 0).
    • When a token starts on a new line, the column offset is calculated relative to 0 on that new line.
  11. Use lsprotocol for LSP type definitions

    main
    The pygls library does not define its own LSP (Language Server Protocol) type definitions. Instead, it relies on the lsprotocol library to provide the official type definitions for all LSP messages, requests, notifications, and parameters. When implementing a language server with pygls, you should use types imported from lsprotocol.types to ensure compatibility with the protocol specification.