Skip to content

raesl.server

Language server module impemented according to the Language Server Protocol.

Reference

cli

ESL Language Server Command Line interface.

serve

serve(port: Optional[int] = None)

Start the ESL Language Server.

Source code in src/raesl/server/cli.py
@click.command("serve")
@click.option(
    "--port",
    "-p",
    default=None,
    type=click.INT,
    help="An optional TCP port to run on, useful for debugging.",
)
def serve(port: Optional[int] = None):
    """Start the ESL Language Server."""
    try:
        from raesl.server.server import ls
    except ImportError:
        logger.error("Missing dependencies. Make sure the 'server' extras are installed.")
        return

    if port is None:
        logger.info("Starting ESL Language Server on STDIO...")
        ls.start_io()
    else:
        logger.info(f"Starting ESL Language Server on port {port}...")
        ls.start_tcp("localhost", port)

config

ESL Language Server config object.

EslConfig

EslConfig()

ESL workspace configuration.

Attributes:

Name Type Description
paths Optional[List[Path]]

ESL input paths derived from workspace config.

output Optional[Path]

Graph output path derived from workspace config.

Source code in src/raesl/server/config.py
def __init__(self):
    self.paths: Optional[List[Path]] = None
    self.output: Optional[Path] = None

get_paths

get_paths(
    ws: Workspace, doc_uri: Optional[str] = None
) -> Optional[List[Path]]

Current set of ESL paths.

Source code in src/raesl/server/config.py
def get_paths(
    self,
    ws: Workspace,
    doc_uri: Optional[str] = None,
) -> Optional[List[Path]]:
    """Current set of ESL paths."""
    if doc_uri is None:
        return self.paths

    doc_path = cleanup_path(doc_uri)

    # If no paths are set or if outside of current scope: return doc_path.
    # Otherwise, we have paths set and the doc_path is part of them.
    if self.paths is None:
        logger.info("No paths set, returning document path...")
        return [doc_path]
    elif doc_path not in self.paths:
        logger.info("Document path outside current set paths, returning that...")
        return [doc_path]
    else:
        logger.info("Returning set paths...")
        return self.paths

parse_config

parse_config(ws: Workspace, cfg: Any)

Parse workspace config.

Source code in src/raesl/server/config.py
def parse_config(self, ws: Workspace, cfg: Any):
    """Parse workspace config."""
    logger.info(f"Parsing config: '{cfg}'...")

    # Handle paths variable.
    paths = getattr(cfg, "eslPaths", False)
    if ws and ws.root_path:
        root = ws.root_path
        logger.info(f"Found root '{root}'.")
    else:
        root = None

    if paths:
        logger.info(f"Parsing config paths {paths}...")
        self.paths = get_esl_paths([cleanup_path(p) for p in paths], root=root)
        logger.info(f"Parsed into '{self.paths}'.")

    elif ws is not None and ws.root_path:
        logger.info("Parsing workspace root...")
        self.paths = get_esl_paths([ws.root_path], root=root)

    else:
        logger.info("No paths found so far, setting None.")
        self.paths = None

    # Handle graph output variable.
    try:
        output = getattr(cfg, "graphPath", None)
        self.output = check_output_path(cleanup_path(output), True, root=root)
    except (ValueError, TypeError):
        self.output = None
    logger.info(f"Set graph output to '{self.output}'.")

    logger.info("Parsed config.")

server

Language Server class module.

EslServer

EslServer()

Bases: LanguageServer

ESL Language Server.

Source code in src/raesl/server/server.py
def __init__(self):
    super().__init__("RaESL", __version__)
    self.config = EslConfig()

update_config async

update_config()

Handle a config update request.

Source code in src/raesl/server/server.py
async def update_config(self):
    """Handle a config update request."""
    self.show_message_log("Refreshing server config...")
    try:
        cfg = await self.get_configuration_async(
            lsp.ConfigurationParams([lsp.ConfigurationItem("", self.CONFIG)])
        )
        self.config.parse_config(self.workspace, cfg[0])
        self.show_message_log("Refreshed server config.")
    except Exception as e:
        self.show_message_log(f"Error occurred while updating config: '{e}'.")

did_change_config async

did_change_config(
    ls: EslServer, params: DidChangeConfigurationParams
)

Config changed handling.

Source code in src/raesl/server/server.py
@ls.feature(lsp.WORKSPACE_DID_CHANGE_CONFIGURATION)
async def did_change_config(ls: EslServer, params: lsp.DidChangeConfigurationParams):
    """Config changed handling."""
    ls.show_message_log("Workspace config changed.")
    await ls.update_config()
    _validate(ls, ls.config.get_paths(ls.workspace))

did_change_watched async

did_change_watched(
    ls: EslServer, params: DidChangeWatchedFilesParams
)

Changed watched files handling.

Source code in src/raesl/server/server.py
@ls.feature(lsp.WORKSPACE_DID_CHANGE_WATCHED_FILES)
async def did_change_watched(ls: EslServer, params: lsp.DidChangeWatchedFilesParams):
    """Changed watched files handling."""
    ls.show_message_log(f"Changed: '{params.changes}")
    await ls.update_config()
    _validate(ls, ls.config.get_paths(ls.workspace))

did_close async

did_close(
    ls: EslServer, params: DidCloseTextDocumentParams
)

Closed document handling.

Source code in src/raesl/server/server.py
@ls.feature(lsp.TEXT_DOCUMENT_DID_CLOSE)
async def did_close(ls: EslServer, params: lsp.DidCloseTextDocumentParams):
    """Closed document handling."""
    ls.show_message_log(f"Closed: '{params.textDocument.uri}'")
    await ls.update_config()
    paths = ls.config.get_paths(ls.workspace) or []
    if cleanup_path(params.textDocument.uri) not in paths:
        ls.publish_diagnostics(doc_uri=params.textDocument.uri, diagnostics=[])
    _validate(ls, paths)

did_open async

did_open(ls: EslServer, params: DidOpenTextDocumentParams)

Opened document handling.

Source code in src/raesl/server/server.py
@ls.feature(lsp.TEXT_DOCUMENT_DID_OPEN)
async def did_open(ls: EslServer, params: lsp.DidOpenTextDocumentParams):
    """Opened document handling."""
    ls.show_message_log(f"Opened: '{params.textDocument.uri}'")
    await ls.update_config()
    _validate(ls, ls.config.get_paths(ls.workspace, params.textDocument.uri))

did_save async

did_save(ls: EslServer, params: DidSaveTextDocumentParams)

Saved document handling.

Source code in src/raesl/server/server.py
@ls.feature(lsp.TEXT_DOCUMENT_DID_SAVE)
async def did_save(ls: EslServer, params: lsp.DidSaveTextDocumentParams):
    """Saved document handling."""
    ls.show_message_log(f"Saved: '{params.textDocument.uri}'")
    await ls.update_config()
    _validate(ls, ls.config.get_paths(ls.workspace, params.textDocument.uri))

set_trace_notification async

set_trace_notification(ls: EslServer, *args)

Unkown notification. Probably a config change.

Source code in src/raesl/server/server.py
@ls.feature("$/setTraceNotification")
async def set_trace_notification(ls: EslServer, *args):
    """Unkown notification. Probably a config change."""
    ls.show_message_log("Unknown notification.")
    await ls.update_config()
    _validate(ls, ls.config.get_paths(ls.workspace))