diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..e5e65321e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ +# CHANGELOG + +## `@krassowski/jupyter-lsp 0.6.1` + +- features + - adds an indicator to the statusbar +- dependencies + - removes unused npm dependencies + +## `@krassowski/jupyter-lsp 0.6.0` + +- features + - allows "rename" action in file editor + - and many other improvements, see the [release notes](https://github.com/krassowski/jupyterlab-lsp/releases/tag/v0.6.0) +- bugfixes + - handles some non-standard diagnostic responses +- testing + - adds browser-based testing for file editor +- dependencies + - requires `jupyter-lsp` + +## `jupyter-lsp 0.6.0` + +- features + - starts language servers on demand + - accepts configuration via Jupyter config system (traitlets) and python + `entry_point`s + - autodetects language servers for bash, CSS, LESS, SASS, Dockerfile, YAML, JS, + TypeScript, JSX, TSX, JSON, YAML diff --git a/py_src/jupyter_lsp/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 77% rename from py_src/jupyter_lsp/CONTRIBUTING.md rename to CONTRIBUTING.md index 5a8964407..d82c0fc40 100644 --- a/py_src/jupyter_lsp/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,168 +1,100 @@ -# Contribute to jupyter-lsp +# Contribute to jupyterlab-lsp and jupyter-lsp :heart: -`jupyter-lsp` is [open source](../../LICENSE) software, and all contributions -conforming to good sense, good taste, and the +`jupyter-lsp` and `jupyterlab-lsp` are [open source](./LICENSE) software, and +all contributions conforming to good sense, good taste, and the [Jupyter Code of Conduct][code-of-conduct] are welcome, and will be reviewed by the contributors, time-permitting. -## How to Help +You can contribute to the project through: -You can contribute to `jupyter-lsp` by: - -- creating [specs](#Specs) +- creating language server [specs](#Specs) - you can publish them yourself (it might be a single file)... - or advocate for adding your spec to the [github repository][jupyterlab-lsp] and its various distributions - these are great first issues, as you might not need to know any python or javascript - improving [documentation](#Documentation) -- tackling Big Issues from the [future roadmap](#Future-Roadmap-Items) +- tackling Big Issues from the [future roadmap](./ROADMAP.md) - improving [testing](#Testing) - reviewing pull requests -## Roadmap - -- release on `pip` -- release on `conda` -- [#49](https://github.com/krassowski/jupyterlab-lsp/issues/49) - cookiecutter for pip-installable specs +## Set up the environment -## Future Roadmap Items +Development requires: -- add hook system to allow serverextensions/kernels to modify, inspect and - react to LSP messages +- `nodejs` 8 or later +- `python` 3.5+ +- `jupyterlab` 1.1 -## Specs +It is recommended to use a virtual environment (e.g. `virtualenv` or `conda env`) +for development. -It is convenient to collect common patterns for connecting to installed language -servers as `pip`-installable packages that Just Work with `jupyter-lsp`. - -If an advanced user installs, locates, and configures, their own language -server it will always win vs an auto-configured one. - -### Writing a spec - -> See the built-in [specs](./specs) for implementations and some -> [helpers](./specs/utils.py). - -A spec is a python function that accepts a single argument, the -`LanguageServerManager`, and returns a dictionary of the form: - -```python -{ - "python-language-server": { # the name of the implementation - "argv": ["python", "-m", "pyls"], # a list of command line arguments - "languages": ["python"] # a list of languages it supports - } -} +```bash +conda env update -n jupyterlab-lsp # create a conda env +source activate jupyterlab-lsp # activate it +# or... +pip install -r requirements-dev.txt # in a virtualenv, probably + # ... and install nodejs, somehow ``` -The spec should only be advertised if the command _could actually_ be run: - -- its runtime (e.g. `julia`, `nodejs`, `python`, `r`, `ruby`) is installed -- the language server itself is installed (e.g. `python-language-server`) +Install `jupyter-lsp` from source in your virtual environment: -#### Common Concerns - -- some language servers need to have their connection mode specified - - the `stdio` interface is the only one supported by `jupyter_lsp` - - PRs welcome to support other modes! -- because of its VSCode heritage, many language servers use `nodejs` - - `LanguageServerManager.nodejs` will provide the location of our best - guess at where a user's `nodejs` might be found -- some language servers are hard to start purely from the command line - - use a helper script to encapsulate some complexity. - - See the [r spec](./specs/r_languageserver.py) for an example - -#### Example: making a pip-installable `cool-language-server` spec - -Consider the following (absolutely minimal) directory structure: - -``` -- setup.py -- jupyter_lsp_my_cool_language_server.py +```bash +python -m pip install -e . ``` -> You should consider adding a LICENSE, some documentation, etc. - -Define your spec: +Enable the server extension: -```python -# jupyter_lsp_my_cool_language_server.py -from shutil import which - - -def cool(app): - cool_language_server = shutil.which("cool-language-server") - - if not cool_language_server: - return {} - - return { - "cool-language-server": { - "argv": [cool_language_server], - "languages": ["cool"] - } - } +```bash +jupyter serverextension enable --sys-prefix --py jupyter_lsp ``` -Tell `pip` how to package your spec: +Install `npm` dependencies, build TypeScript packages, and link +to JupyterLab for development: -```python -# setup.py -import setuptools -setuptools.setup( - name="jupyter-lsp-my-cool-language-server", - py_modules=["jupyter_lsp_my_cool_language_server"], - entry_points={ - "jupyter_lsp_spec_v0": [ - "cool-language-server": - "jupyter_lsp_my_cool_language_server:cool" - ] - } -) +```bash +jlpm +jlpm build +jlpm lab:link ``` -Test it! +## Frontend Development + +To rebuild the packages and the JupyterLab app: ```bash -python -m pip install -e . +jlpm build +jupyter lab build ``` -Build it! +To watch the files and build continuously: ```bash -python setup.py sdist bdist_wheel +jlpm build --watch # leave this running... +jupyter lab --watch # ...in another terminal ``` -## Contributing to `jupyter-lsp` - -### Set up the environment +To check and fix code style: ```bash -conda env update -n jupyterlab-lsp # create a conda env -source activate jupyterlab-lsp # activate it -# or... -pip install -r requirements-dev.txt # in a virtualenv, probably - # ... and install nodejs, somehow +jlpm lint ``` -Install a development version from `master` in your virtual environment: +To run test the suite: ```bash -python -m pip install -e . -jupyter labextension install . +jlpm test ``` -## Testing `jupyter-lsp` +## Server Development -### Unit & Code Style Tests +### Testing `jupyter-lsp` ```bash python scripts/utest.py ``` -### Browser-based Acceptance Tests +## Browser-based Acceptance Tests The browser tests will launch JupyterLab on a random port and exercise the Language Server features with [Robot Framework][] and [SeleniumLibrary][]. @@ -171,7 +103,7 @@ Language Server features with [Robot Framework][] and [SeleniumLibrary][]. [seleniumlibrary]: https://github.com/robotframework/seleniumlibrary First, ensure you've prepared JupyterLab for `jupyterlab-lsp` -[development](../../README.md#development). +[frontend](#frontend-development) and [server](#server-development) development. Prepare the enviroment: @@ -179,11 +111,9 @@ Prepare the enviroment: conda env update -n jupyterlab-lsp --file environment-atest.yml # or pip install -r requirements-atest.txt # ... and install geckodriver, somehow +apt-get install firefox-geckodriver # ... e.g. on debian/ubuntu ``` -> Ubuntu users can install geckodriver with `apt install firefox-geckodriver`. -> Ensure you have run `jupyter labextension install .` in the root of the repository. - Run the tests: ```bash @@ -239,8 +169,108 @@ black py_src > - sphinx > - one of the sphinx/ipynb connectors -[language-server]: https://microsoft.github.io/language-server-protocol/specification -[jupyter-server-proxy]: https://github.com/jupyterhub/jupyter-server-proxy -[lsp-implementations]: https://microsoft.github.io/language-server-protocol/implementors/servers [jupyterlab-lsp]: https://github.com/krassowski/jupyterlab-lsp.git [code-of-conduct]: https://github.com/jupyter/governance/blob/master/conduct/code_of_conduct.md + +### Specs + +It is convenient to collect common patterns for connecting to installed language +servers as `pip`-installable packages that Just Work with `jupyter-lsp`. + +If an advanced user installs, locates, and configures, their own language +server it will always win vs an auto-configured one. + +#### Writing a spec + +> See the built-in [specs](./specs) for implementations and some +> [helpers](./specs/utils.py). + +A spec is a python function that accepts a single argument, the +`LanguageServerManager`, and returns a dictionary of the form: + +```python +{ + "python-language-server": { # the name of the implementation + "argv": ["python", "-m", "pyls"], # a list of command line arguments + "languages": ["python"] # a list of languages it supports + } +} +``` + +The spec should only be advertised if the command _could actually_ be run: + +- its runtime (e.g. `julia`, `nodejs`, `python`, `r`, `ruby`) is installed +- the language server itself is installed (e.g. `python-language-server`) + +##### Common Concerns + +- some language servers need to have their connection mode specified + - the `stdio` interface is the only one supported by `jupyter_lsp` + - PRs welcome to support other modes! +- because of its VSCode heritage, many language servers use `nodejs` + - `LanguageServerManager.nodejs` will provide the location of our best + guess at where a user's `nodejs` might be found +- some language servers are hard to start purely from the command line + - use a helper script to encapsulate some complexity. + - See the [r spec](./specs/r_languageserver.py) for an example + +##### Example: making a pip-installable `cool-language-server` spec + +Consider the following (absolutely minimal) directory structure: + +``` +- setup.py +- jupyter_lsp_my_cool_language_server.py +``` + +> You should consider adding a LICENSE, some documentation, etc. + +Define your spec: + +```python +# jupyter_lsp_my_cool_language_server.py +from shutil import which + + +def cool(app): + cool_language_server = shutil.which("cool-language-server") + + if not cool_language_server: + return {} + + return { + "cool-language-server": { + "argv": [cool_language_server], + "languages": ["cool"] + } + } +``` + +Tell `pip` how to package your spec: + +```python +# setup.py +import setuptools +setuptools.setup( + name="jupyter-lsp-my-cool-language-server", + py_modules=["jupyter_lsp_my_cool_language_server"], + entry_points={ + "jupyter_lsp_spec_v0": [ + "cool-language-server": + "jupyter_lsp_my_cool_language_server:cool" + ] + } +) +``` + +Test it! + +```bash +python -m pip install -e . +``` + +Build it! + +```bash +python setup.py sdist bdist_wheel +``` diff --git a/LANGUAGESERVERS.md b/LANGUAGESERVERS.md new file mode 100644 index 000000000..add757d78 --- /dev/null +++ b/LANGUAGESERVERS.md @@ -0,0 +1,137 @@ +# Language Servers + +`jupyter-lsp` does not come with any Language Servers! However, we will try to use +them if they _are_ installed and we know about them (you can disable this behavior +by configuring [`autodetect`](#autodetect)). + +Use a package manager to install a [language server][lsp-implementations] +(also [this list][langserver]) from the tables below: these implementations are +tested to work with `jupyter-lsp`. + +| language | `npm install (-g)`, or `yarn/jlpm add (-g)` | +| ------------------------- | :-----------------------------------------: | +| bash | `bash-language-server` | +| css
less
sass | `vscode-css-languageserver-bin` | +| docker | `dockerfile-language-server-nodejs` | +| html | `vscode-html-languageserver-bin` | +| javascript
typescript | `javascript-typescript-langserver` | +| json | `vscode-json-languageserver-bin` | +| markdown | `unified-language-server` | +| yaml | `yaml-language-server` | + +| language | `conda install -c conda-forge` | language-specific package manager | +| -------- | :----------------------------: | :-----------------------------------------------: | +| python | `python-language-server` | `pip install python-language-server` | +| r | `r-languageserver` | `Rscript -e 'install.packages("languageserver")'` | + +[language-server]: https://microsoft.github.io/language-server-protocol/specification +[langserver]: https://langserver.org +[jupyter-server-proxy]: https://github.com/jupyterhub/jupyter-server-proxy +[lsp-implementations]: https://microsoft.github.io/language-server-protocol/implementors/servers +[jupyter-lsp]: https://github.com/krassowski/jupyterlab-lsp.git +[jupyterlab]: https://github.com/jupyterlab/jupyterlab + +Don't see an implementation for the language server you need? You can +[bring your own language server](#adding-custom-language-servers). + +> Please consider [contributing your language server spec](../../CONTRIBUTING.md#spec) +> to `jupyter-lsp`! + +## Adding custom language servers + +### Jupyter config via `traitlets` + +Like the Jupyter Notebook server, JupyterHub and other Jupyter interactive computing +tools, `jupyter-lsp` can be configured via [Python or JSON files][notebook-config] +in _well-known locations_. You can find out where to put them on your system with: + +[notebook-config]: https://jupyter-notebook.readthedocs.io/en/stable/config.html + +```bash +jupyter --paths +``` + +They will be merged from bottom to top, and the directory where you launch your +`notebook` server wins, making it easy to check in to version control. + +```python +# ./jupyter_notebook_config.json ---------- unique! ----------- +# | | +# or e.g. V V +# $PREFIX/etc/jupyter/jupyter_notebook_config.d/a-language-server-implementation.json +{ + "LanguageServerManager": { + "language_servers": { + "a-language-server-implementation": { + "argv": ["/absolute/path/to/a-language-server", "--stdio"], + "languages": ["a-language"] + } + } + } +} +``` + +More complex configurations that can't be hard-coded may benefit from the python approach: + +```py +# jupyter_notebook_config.py +import shutil + +# c is a magic, lazy variable +c.LanguageServerManager.language_servers = { + "a-language-server-implementation": { + # if installed as a binary + "argv": [shutil.which("a-language-server")], + "languages": ["a-language"] + }, + "another-language-implementation": { + # if run like a script + "argv": [shutil.which("another-language-interpreter"), "another-language-server"], + "languages": ["another-language"] + } +} +``` + +### Python `entry_points` + +`pip`-installable packages in the same environment as the Jupyter `notebook` server +can be automatically detected as providing a language server spec. These are a +little more involved: see [CONTRIBUTING](../../CONTRIBUTING.md). + +# Configuration Options + +Like `language_servers`, these can be configured via `jupyter_notebook_config.json` +(or .py) or via command line arguments to `jupyter notebook` or `jupyter lab`. + +## nodejs + +> default: autodetect + +A custom absolute path to your `nodejs` executable. + +## autodetect + +> default: True + +`jupyter-lsp` will look for all [known language servers](#installing-language-servers). +User-configured `language_servers` of the same implementation will be preferred +over `autodetect`ed ones. + +## node_roots + +> default: [] + +Absolute paths to search for `node_modules`, such as `nodejs`-backed language servers. +The order is, roughly: + +- the folder where `notebook` or `lab` was launched +- the JupyterLab `staging` folder +- wherever `conda` puts global node modules +- wherever some other conventions put it + +## extra_node_roots + +> default: [] + +Additional places `jupyter-lsp` will look for `node_modules`. These will be checked +before `node_roots` diff --git a/README.md b/README.md index 8a6386e3c..cea2b6961 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,77 @@ -# Language Server Protocol integration for JupyterLab +# Language Server Protocol integration for Jupyter(Lab) [![Build Status](https://travis-ci.org/krassowski/jupyterlab-lsp.svg?branch=master)](https://travis-ci.org/krassowski/jupyterlab-lsp) [![Build Status](https://dev.azure.com/krassowskimichal/jupyterlab-lsp/_apis/build/status/jupyterlab-lsp?branchName=master)](https://dev.azure.com/krassowskimichal/jupyterlab-lsp/_build/latest?definitionId=1&branchName=master) [![codebeat badge](https://codebeat.co/badges/f55d0f28-8a84-4199-bc88-f2c306a9ce65)](https://codebeat.co/projects/github-com-krassowski-jupyterlab-lsp-master) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/krassowski/jupyterlab-lsp/master?urlpath=lab%2Ftree%2Fexamples%2FPython.ipynb) -_This extension is in its early days, but you are welcome to check it out, leave feedback and/or a PR_ +> _This project is in its early days, but you are welcome to check it out, leave feedback and/or a PR_ -## Features overview: +Quick Links: **[Installation](#installation) | [Language Servers](./LANGUAGESERVERS.md) | [Updating](#updating) | [Changelog](./CHANGELOG.md) | [Roadmap](./ROADMAP.md) | [Contributing](./CONTRIBUTING.md)** -### Implemented +## Features -Examples below are for Python, but it works as well for R: +> Examples below are for Python, but work for R as well -- hover over any piece of code; if an underline appears, you can press Ctrl to get a tooltip with function/class signature, module documentation or any other piece of information that the language server provides +### Hover - ![hover](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/hover.png) +Hover over any piece of code; if an underline appears, you can press Ctrl +to get a tooltip with function/class signature, module documentation or any other +piece of information that the language server provides -- linting: critical errors have red underline, warnings are orange, etc. Hover over the underlined code to see the linter's message +![hover](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/hover.png) - ![inspections](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/inspections.png) +### Diagnostics -- go to definition: use the context menu entries to jump to definitions +Critical errors have red underline, warnings are orange, etc. Hover +over the underlined code to see a more detailed message - ![jump](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/jump_to_definition.png) +![inspections](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/inspections.png) -- highlight usages: just place your cursor on a variable, function etc and all the usages will be highlighted +### Jump to Definition -- auto invocation of completer on certain characters, for example '.' (dot) in Python +Use the context menu entries to jump to definitions - ![invoke](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/auto_invoke.png) +![jump](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/jump_to_definition.png) -- automatic signature suggestions +### Highlight References - ![signature](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/signature.png) +Place your cursor on a variable, function, etc and all the usages will be highlighted -- advanced autocompletion (even when the kernel is off); +### Automatic Completion - ![autocompletion](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/autocompletion.png) +Certain characters, for example '.' (dot) in Python, will automatically trigger +completion - when a kernel is available the suggestions from the kernel (such as keys of a dict and columns of a DataFrame autocompletion) are merged with the suggestions from LSP (currently only in notebook). +![invoke](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/auto_invoke.png) -New in 0.6.0: +### Automatic Signature Suggestions -- automated LSP servers start and traitlets-based configuration -- "rename" action in file editor -- and many other improvements, see the [release notes](https://github.com/krassowski/jupyterlab-lsp/releases/tag/v0.6.0). +Function signatures will automatically be displayed -New in 0.6.1: +![signature](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/signature.png) -- removed unused dependencies -- added an indicator to the statusbar +### Kernel-less Autocompletion -### Coming soon: +Advanced static-analysis autocompletion without a running kernel -- improved code navigation when there are multiple jump targets -- autocompleter with documentation and sorting based on LSP suggestions -- system of settings, including options: - - to enable aggressive autocompletion (like in hinterland) - - to change the verbosity of signature hints (whether to show documentation, number of lines to be shown) -- "rename" action in notebooks -- gutter with linter results (low priority) -- use the kernel session for autocompletion in FileEditor if available (PR welcome) +![autocompletion](https://raw.githubusercontent.com/krassowski/jupyterlab-lsp/master/examples/screenshots/autocompletion.png) -If a feature you need is not on the lists above, please feel free to suggest it by opening a new [issue](https://github.com/krassowski/jupyterlab-lsp/issues). - -#### Hints - -- just like in old notebooks, you can still use the built-in Shift + Tab to get a signature in JupyterLab. - This extension behaves well with this feature. +> When a kernel is available the suggestions from the kernel (such as keys of a +> dict and columns of a DataFrame autocompletion) are merged with the suggestions +> from the Language Server (currently only in notebook). ## Prerequisites - JupyterLab >=1.1,<1.2 +- Python 3.5+ +- nodejs 8+ ## Installation -For 0.6 version: +For the current stable version: -1. install and enable the server extension: +1. install the server extension: ```bash pip install jupyter-lsp - jupyter serverextension enable --sys-prefix --py jupyter_lsp ``` 2. install the frontend extension: @@ -88,20 +80,35 @@ For 0.6 version: jupyter labextension install @krassowski/jupyterlab-lsp ``` -3. install LSP servers for languages of your choice; for example, for Python ([pyls](https://github.com/palantir/python-language-server)) and R ([languageserver](https://github.com/REditorSupport/languageserver)) servers, use: +3. install LSP servers for languages of your choice; for example, for Python + ([pyls](https://github.com/palantir/python-language-server)) and + R ([languageserver](https://github.com/REditorSupport/languageserver)) servers: ```bash pip install python-language-server[all] R -e 'install.packages("languageserver")' ``` - Please see our full list of [supported language servers](./py_src/jupyter_lsp/README.md#installing-language-servers) which includes installation hints for the common package managers (npm/pip/conda). - In general, any LSP server from the [Microsoft's list](https://microsoft.github.io/language-server-protocol/implementors/servers/) should work after [some additional configuration](./py_src/jupyter_lsp/CONTRIBUTING.md#specs). + or from `conda-forge` - Note: it may be worth visiting the repository of each server you install as many provide additional configuration options. + ```bash + conda install -c conda-forge python-language-server r-languageserver + ``` -4. (Optional) to enable opening files outside of the root directory (the place where you start JupyterLab), - create `.lsp_symlink` and symlink your `home`, or any other location which includes the files that you wish to make possible to open in there: + Please see our full list of + [supported language servers](./LANGUAGESERVERS.md) + which includes installation hints for the common package managers (npm/pip/conda). + In general, any LSP server from the + [Microsoft list](https://microsoft.github.io/language-server-protocol/implementors/servers/) + should work after [some additional configuration](./CONTRIBUTING.md#specs). + + Note: it may be worth visiting the repository of each server you install as + many provide additional configuration options. + +4. (Optional, Linux/OSX-only) to enable opening files outside of the root + directory (the place where you start JupyterLab), create `.lsp_symlink` and + symlink your `/home`, or any other location which includes the files that you + wish to make possible to open in there: ```bash mkdir .lsp_symlink @@ -109,62 +116,30 @@ For 0.6 version: ln -s /home home ``` - If your user does not have sufficient permissions to traverse the entire path, you will not be able to open the file. A more detailed guide on symlinking (written for a related jupyterlab-go-to-definition extension) is available [here](https://github.com/krassowski/jupyterlab-go-to-definition/blob/master/README.md#which-directories-to-symlink). + If your user does not have sufficient permissions to traverse the entire path, + you will not be able to open the file. A more detailed guide on symlinking + (written for a related jupyterlab-go-to-definition extension) is available + [here](https://github.com/krassowski/jupyterlab-go-to-definition/blob/master/README.md#which-directories-to-symlink). -### Updating the extension +### Updating -To update already installed extension: +To update previously installed extensions: ```bash pip install -U jupyter-lsp jupyter labextension update @krassowski/jupyterlab-lsp ``` -#### Getting the latest alpha/beta/RC version - -Use install command (update does not seem to work) appending `@version` to the extension name, like this: - -```bash -jupyter labextension install @krassowski/jupyterlab-lsp@0.6.1 -``` - -## Development - -For a development install (requires `nodejs` 8 or later and `jupyterlab` 1.1), -run the following in the repository directory: - -```bash -jlpm -jlpm build -jlpm lab:link -``` - -To rebuild the packages and the JupyterLab app: - -```bash -jlpm build -jupyter lab build -``` - -To watch the files and build continuously: - -```bash -jlpm build --watch # leave this running... -jupyter lab --watch # ...in another terminal -``` - -To check and fix code style: - -```bash -jlpm lint -``` +### Getting the latest alpha/beta/RC version -To run test the suite: +Use `install` command (update does not seem to work) appending `@<0.x.y.rc-z>` to the +extension name, like this: ```bash -jlpm test +jupyter labextension install @krassowski/jupyterlab-lsp@0.7.0-rc.0 ``` ## Acknowledgements -This would not be possible if not the fantastic work at [wylieconlon/lsp-editor-adapter](https://github.com/wylieconlon/lsp-editor-adapter). +This would not be possible without the fantastic initial work at +[wylieconlon/lsp-editor-adapter](https://github.com/wylieconlon/lsp-editor-adapter). diff --git a/RELEASE.md b/RELEASE.md index 1c8541a21..0164b1e8f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,15 +4,21 @@ Releases may require building both the python package and nodejs packages. ## Updating Version Strings -The version for PyPI must be updated in two places: +Check the version strings across the various files: -- `py_src/jupyter_lsp/_version.py` +```bash +python scripts/integrity.py +``` + +> TODO: create a `release.py` script + +The PyPI version must be updated in at least two places: + +- `py_src/jupyter_lsp/_version.py` (canonical) - `azure-pipelines.yml` -The version for npm must be updated in five places (TODO create a `release.sh` or `release.py` script): +The npm version must be updated in at least three places -- `package.json` +- `packages/jupyterlab-lsp/package.json` (canonical) - `azure-pipelines.yml` -- `packages/jupyterlab-lsp/package.json` - `packages/metapackage/package.json` -- `README.md` diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 000000000..c56b53399 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,23 @@ +# Roadmap + +> If a feature you need is not on the lists above, please feel free to suggest it +> by opening a new [issue](https://github.com/krassowski/jupyterlab-lsp/issues). + +## Front End + +- improved code navigation when there are multiple jump targets +- autocompleter with documentation and sorting based on LSP suggestions +- system of settings, including options: + - to enable aggressive autocompletion (like in hinterland) + - to change the verbosity of signature hints (whether to show documentation, number of lines to be shown) +- "rename" action in notebooks +- gutter with linter results (low priority) +- use the kernel session for autocompletion in FileEditor if available (PR welcome) + +## Backend + +- release on `conda` +- [#49](https://github.com/krassowski/jupyterlab-lsp/issues/49) + cookiecutter for pip-installable specs +- add hook system to allow serverextensions/kernels to modify, inspect and + react to LSP messages diff --git a/py_src/jupyter_lsp/README.md b/py_src/jupyter_lsp/README.md index 0c6b80d11..acd53bc02 100644 --- a/py_src/jupyter_lsp/README.md +++ b/py_src/jupyter_lsp/README.md @@ -3,143 +3,17 @@ Multi-[Language Server][language-server] WebSocket proxy for your Jupyter `notebook` or `lab` server. For Python 3.5+. -See the parent of this repository, [jupyterlab-lsp](https://github.com/krassowski/jupyterlab-lsp) for the -reference client implementation for [JupyterLab][]. +> See the parent of this repository, +> [jupyterlab-lsp](https://github.com/krassowski/jupyterlab-lsp) for the +> reference client implementation for [JupyterLab][]. -## Installing language servers +# Language Servers -`jupyter-lsp` does not come with any Language Servers! However, we will try to use -them if they _are_ installed and we know about them (you can disable this behavior -by configuring [`autodetect`](#autodetect)). - -Use a package manager to install a [language server][lsp-implementations] -(also [this list][langserver]) from the tables below: these implementations are -tested to work with `jupyter-lsp`. - -| language | `npm install (-g)`, or `yarn/jlpm add (-g)` | -| ------------------------- | :-----------------------------------------: | -| bash | `bash-language-server` | -| css
less
sass | `vscode-css-languageserver-bin` | -| docker | `dockerfile-language-server-nodejs` | -| html | `vscode-html-languageserver-bin` | -| javascript
typescript | `javascript-typescript-langserver` | -| json | `vscode-json-languageserver-bin` | -| markdown | `unified-language-server` | -| yaml | `yaml-language-server` | - -| language | `conda install -c conda-forge` | language-specific package manager | -| -------- | :----------------------------: | :-----------------------------------------------: | -| python | `python-language-server` | `pip install python-language-server` | -| r | `r-languageserver` | `Rscript -e 'install.packages("languageserver")'` | +`jupyter-lsp` does not come with any Language Servers! Learn more about installing +and configuring [language servers](../../LANGUAGESERVERS.md) [language-server]: https://microsoft.github.io/language-server-protocol/specification [langserver]: https://langserver.org -[jupyter-server-proxy]: https://github.com/jupyterhub/jupyter-server-proxy [lsp-implementations]: https://microsoft.github.io/language-server-protocol/implementors/servers [jupyter-lsp]: https://github.com/krassowski/jupyterlab-lsp.git [jupyterlab]: https://github.com/jupyterlab/jupyterlab - -Don't see an implementation for the language server you need? You can -[bring your own language server](#adding-custom-language-servers). - -> Please consider [contributing your language server spec](./CONTRIBUTING.md#spec) -> to `jupyter-lsp`! - -## Adding custom language servers - -### Jupyter config via `traitlets` - -Like the Jupyter Notebook server, JupyterHub and other Jupyter interactive computing -tools, `jupyter-lsp` can be configured via [Python or JSON files][notebook-config] -in _well-known locations_. You can find out where to put them on your system with: - -[notebook-config]: https://jupyter-notebook.readthedocs.io/en/stable/config.html - -```bash -jupyter --paths -``` - -They will be merged from bottom to top, and the directory where you launch your -`notebook` server wins, making it easy to check in to version control. - -```python -# ./jupyter_notebook_config.json ---------- unique! ----------- -# | | -# or e.g. V V -# $PREFIX/etc/jupyter/jupyter_notebook_config.d/a-language-server-implementation.json -{ - "LanguageServerManager": { - "language_servers": { - "a-language-server-implementation": { - "argv": ["/absolute/path/to/a-language-server", "--stdio"], - "languages": ["a-language"] - } - } - } -} -``` - -More complex configurations that can't be hard-coded may benefit from the python approach: - -```py -# jupyter_notebook_config.py -import shutil - -# c is a magic, lazy variable -c.LanguageServerManager.language_servers = { - "a-language-server-implementation": { - # if installed as a binary - "argv": [shutil.which("a-language-server")], - "languages": ["a-language"] - }, - "another-language-implementation": { - # if run like a script - "argv": [shutil.which("another-language-interpreter"), "another-language-server"], - "languages": ["another-language"] - } -} -``` - -### Python `entry_points` - -`pip`-installable packages in the same environment as the Jupyter `notebook` server -can be automatically detected as providing a language server spec. These are a -little more involved: see [CONTRIBUTING](./CONTRIBUTING.md). - -# Configuration Options - -Like `language_servers`, these can be configured via `jupyter_notebook_config.json` -(or .py) or via command line arguments to `jupyter notebook` or `jupyter lab`. - -## nodejs - -> default: autodetect - -A custom absolute path to your `nodejs` executable. - -## autodetect - -> default: True - -`jupyter-lsp` will look for all [known language servers](#installing-language-servers). -User-configured `language_servers` of the same implementation will be preferred -over `autodetect`ed ones. - -## node_roots - -> default: [] - -Absolute paths to search for `node_modules`, such as `nodejs`-backed language servers. -The order is, roughly: - -- the folder where `notebook` or `lab` was launched -- the JupyterLab `staging` folder -- wherever `conda` puts global node modules -- wherever some other conventions put it - -## extra_node_roots - -> default: [] - -Additional places `jupyter-lsp` will look for `node_modules`. These will be checked -before `node_roots` diff --git a/scripts/integrity.py b/scripts/integrity.py index da6fa2934..7a77a5e80 100644 --- a/scripts/integrity.py +++ b/scripts/integrity.py @@ -101,13 +101,6 @@ def test_ts_package_integrity(name, info, the_meta_package): jsonschema.validators.Draft7Validator(schema_instance) -def test_ts_readme(): - version = PACKAGES[MAIN_NAME][1]["version"] - assert ( - "{}@{}".format(MAIN_NAME, version) in MAIN_README.read_text() - ), "README.md is out of sync vs {}".format(version) - - @pytest.mark.parametrize( "path", map(