diff --git a/.gitignore b/.gitignore index 8a30d25..e7af96b 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,7 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml + +src/multilspy/language_servers/eclipse_jdtls/static/ +src/multilspy/language_servers/omnisharp/static/ +src/multilspy/language_servers/rust_analyzer/static/ \ No newline at end of file diff --git a/README.md b/README.md index 5cd7cec..2deae51 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,86 @@ -# Project +# Multilspy: LSP client library in Python to build applications around language servers -> This repo has been populated by an initial template to help get you started. Please -> make sure to update the content to build a great experience for community-building. +## Introduction +This repository hosts multilspy, a library developed as part of research conducted for ["Monitor-Guided Decoding of Code LMs with Static Analysis of Repository Context"](https://neurips.cc/virtual/2023/poster/70362) appearing at NeurIPS 2023 (["Guiding Language Models of Code with Global Context using Monitors"](https://arxiv.org/abs/2306.10763) on Arxiv). The work introduces Monitor-Guided Decoding (MGD) for code generation using Language Models, where a monitor uses static analysis to guide the decoding, ensuring that the generated code follows various correctness properties, like absence of hallucinated symbol names, valid order of method calls, etc. For further details about Monitor-Guided Decoding, please refer to the paper and GitHub repository [microsoft/monitors4codegen](https://github.com/microsoft/monitors4codegen). -As the maintainer of this project, please make a few updates: +`multilspy` is a cross-platform library that we have built to set up and interact with various language servers in a unified and easy way. Using `multilspy` makes it easy to create a language server client to easily obtain and use results of various static analyses provided by a large variety of language servers that communicate over the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/). `multilspy` is intended to be used to query various language servers, without having to worry about setting up their configurations and implementing the client-side of language server protocol. `multilspy` currently supports running language servers for Java, Rust, C# and Python, and we aim to expand this list with the help of the community. `multilspy` intends to ease the process of using language servers, by abstracting the setting up of the language servers, performing language-specific configuration and handling communication with the server over the json-rpc based protocol, while exposing a simple interface to the user. -- Improving this README.MD file to provide a great experience -- Updating SUPPORT.MD with content about this project's support experience -- Understanding the security reporting process in SECURITY.MD -- Remove this section from the README +[Language servers]((https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/)) are tools that perform a variety of static analyses on source code and provide useful information such as type-directed code completion suggestions, symbol definition locations, symbol references, etc., over the [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/). + +Since LSP is language-agnostic, `multilspy` can provide the results for static analyses of code in different languages over a common interface. `multilspy` is easily extensible to any language that has a Language Server and currently supports Java, Rust, C# and Python and we aim to support more language servers from the [list of language server implementations](https://microsoft.github.io/language-server-protocol/implementors/servers/). + +Some of the analyses results that `multilspy` can provide are: +- Finding the definition of a function or a class ([textDocument/definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition)) +- Finding the callers of a function or the instantiations of a class ([textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references)) +- Providing type-based dereference completions ([textDocument/completion](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion)) +- Getting information displayed when hovering over symbols, like method signature ([textDocument/hover](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover)) +- Getting list/tree of all symbols defined in a given file, along with symbol type like class, method, etc. ([textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol)) +- Please create an issue/PR to add any other LSP request not listed above + +## Installation +To install `multilspy` using pip, execute the following command: +``` +pip install https://github.com/microsoft/multilspy/archive/main.zip +``` + +### Usage +Example usage: +```python +from multilspy import SyncLanguageServer +from multilspy.multilspy_config import MultilspyConfig +from multilspy.multilspy_logger import MultilspyLogger +... +config = MultilspyConfig.from_dict({"code_language": "java"}) # Also supports "python", "rust", "csharp" +logger = MultilspyLogger() +lsp = SyncLanguageServer.create(config, logger, "/abs/path/to/project/root/") +with lsp.start_server(): + result = lsp.request_definition( + "relative/path/to/code_file.java", # Filename of location where request is being made + 163, # line number of symbol for which request is being made + 4 # column number of symbol for which request is being made + ) + result2 = lsp.request_completions( + ... + ) + result3 = lsp.request_references( + ... + ) + result4 = lsp.request_document_symbols( + ... + ) + result5 = lsp.request_hover( + ... + ) + ... +``` + +`multilspy` also provides an asyncio based API which can be used in async contexts. Example usage (asyncio): +```python +from multilspy import LanguageServer +... +lsp = LanguageServer.create(...) +async with lsp.start_server(): + result = await lsp.request_definition( + ... + ) + ... +``` + +The file [src/multilspy/language_server.py](src/multilspy/language_server.py) provides the `multilspy` API. Several tests for `multilspy` present under [tests/multilspy/](tests/multilspy/) provide detailed usage examples for `multilspy`. The tests can be executed by running: +```bash +pytest tests/multilspy +``` + +## Frequently Asked Questions (FAQ) +### ```asyncio``` related Runtime error when executing the tests for MGD +If you get the following error: +``` +RuntimeError: Task cb=[_chain_future.._call_set_state() at + python3.8/asyncio/futures.py:367]> got Future attached to a different loop python3.8/asyncio/locks.py:309: RuntimeError +``` + +Please ensure that you create a new environment with Python ```>=3.10```. For further details, please have a look at the [StackOverflow Discussion](https://stackoverflow.com/questions/73599594/asyncio-works-in-python-3-10-but-not-in-python-3-8). ## Contributing