Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the pygls-playground extension a workspace local extension #458

Merged
merged 6 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions .github/workflows/json-extension.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
name: vscode-playground
name: pygls-playground

on:
- push
- pull_request
push:
branches:
- main

pull_request:
branches:
- main

jobs:
build:
Expand All @@ -11,29 +16,24 @@ jobs:
defaults:
run:
shell: bash
working-directory: examples/vscode-playground
working-directory: .vscode/extensions/pygls-playground

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- uses: actions/setup-python@v2
- uses: actions/setup-python@v5
with:
python-version: "3.x"

- uses: actions/setup-node@v2
with:
node-version: "16"

- uses: actions/cache@v2
- uses: actions/setup-node@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('examples/vscode-playground/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
node-version: "18.x"
cache: 'npm'
cache-dependency-path: '.vscode/extensions/pygls-playground/package-lock.json'

- name: Install dependencies
run: |
npm i
npm ci
npm i vsce

- name: Lint
Expand Down Expand Up @@ -65,10 +65,10 @@ jobs:
npx vsce ls | grep out/extension.js

- name: Upload VSIX
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: vscode-playground-vsix
name: pygls-playground-vsix
# The path must be rooted from the directory GitHub Actions starts
# from, not the working-directory.
path: examples/vscode-playground/*.vsix
path: .vscode/extensions/pygls-playground/*.vsix
if-no-files-found: error
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,3 @@ venv.bak/
.dmypy.json

/pyodide_testrunner

# VS Code settings
.vscode/
!examples/servers/.vscode
131 changes: 131 additions & 0 deletions .vscode/extensions/pygls-playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Pygls Playground

![Screenshot of the pygls-playground extension in action](https://user-images.githubusercontent.com/2675694/260591942-b7001a7b-3081-439d-b702-5f8a489856db.png)

This VSCode extension aims to serve two purposes.

- Provide an environment in which you can easily experiment with the pygls framework by trying some of our example servers - or by writing your own

- Provide a minimal example of what it takes to integrate a pygls powered language server into VSCode.

For an example of a more complete VSCode client, including details on how to bundle your Python code with the VSCode extension itself you may also be interested in Microsoft's [template extension for Python tools](https://github.com/microsoft/vscode-python-tools-extension-template).

## Setup

### Install Server Dependencies

Open a terminal in the repository's root directory

1. Create a virtual environment
```
python -m venv env
```

1. Activate the environment
```
source ./env/bin/activate
```

1. Install `pygls`
```
python -m pip install -e .
```

### Install Client Dependencies

Open terminal in the same directory as this file and execute following commands:

1. Install node dependencies

```
npm install --no-save
```
1. Compile the extension

```
npm run compile
```
Alternatively you can run `npm run watch` if you are going to be actively working on the extension itself.

### Run Extension (VSCode v1.89+)

> [!IMPORTANT]
> In order for VSCode to recognise `pygls-playground` as a valid extension, you need to complete the setup steps above **before** opening this repo inside VSCode.
> If you opened VSCode before compiling the extension, you will have to run the `Developer: Reload Window` command through the command palette (`Ctrl+Shift+P`)

1. Open the `pygls` repository in VSCode

1. Goto the `Extensions` tab (`Ctrl+Shift+X`), find the `pygls-playground` extension in the *Recommended* section (not by searching in the marketplace!) and click the `Install Workspace Extension` button.
**If the button only says "Install", you've not found the right version of this extension**

1. You will need to make sure that VSCode is using a virtual environment that contains an installation of `pygls`.
The `Python: Select Interpreter` command can be used to pick the correct one.

Alternatively, you can set the `pygls.server.pythonPath` option in the `.vscode/settings.json` file

### Run Extension (VSCode v1.88 and older)

1. Open this directory in VS Code

1. The playground relies on the [Python extension for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-python.python) for choosing the appropriate Python environment in which to run the example language servers.
If you haven't already, you will need to install it and reload the window.

1. Open the Run and Debug view (`ctrl + shift + D`)

1. Select `Launch Client` and press `F5`, this will open a second VSCode window with the `pygls-playground` extension enabled.

1. You will need to make sure that VSCode is using a virtual environment that contains an installation of `pygls`.
The `Python: Select Interpreter` command can be used to pick the correct one.

Alternatively, you can set the `pygls.server.pythonPath` option in the `.vscode/settings.json` file

## Configuration

By default, the `pygls-playground` extension is configured to run the example `code_actions.py` server which you can find in the `examples/servers` folder of this repository.
(For best results, try opening the `examples/servers/workspace/sums.txt` file).

However, the `.vscode/settings.json` file in this repository can be used alter this and more.

### Selecting a server

> [!TIP]
> See the [README](../../../examples/servers/README.md) in the `examples/servers` folder for details on the available servers and which files they work best with.

To select a different example server, change the `pygls.server.launchScript` setting to the name of the server you wish to run

### Selecting the working directory

> [!TIP]
> Cryptic `Error: spawn /.../python ENOENT` messages are often due to the extension using an incorrect working directory.

If everything works as expected, the `pygls-playground` extension **should** default to using the `examples/servers/` folder as its working directory.

If this is not the case, or you want to change it to something else, you can change the `pygls.server.cwd` option

### Selecting documents

Language servers typically specialise in a relatively small number of file types, so a client will only ask a server about documents

The `code_actions.py` example is intended to be used with `plaintext` files (e.g. the provided `sums.txt` file). To use a server with different file types you can modify the `pygls.client.documentSelector` option

For example to use a server with `json` files:

```
"pygls.client.documentSelector": [
{
"scheme": "file",
"language": "json"
},
],
```

You can find the full list of known language identifiers [here](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers).

See the [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentFilter) for details on all the available options that can be passed to the `pygls.client.documentSelector` option.

### Debugging the server

To debug the language server set the `pygls.server.debug` option to `true`.
The server should be restarted and the debugger connect automatically.

You can control the host and port that the debugger uses through the `pygls.server.debugHost` and `pygls.server.debugPort` options.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "Open Law Library",
"repository": "https://github.com/openlawlibrary/pygls",
"license": "Apache-2.0",
"version": "1.0.2",
"version": "1.3.1",
"publisher": "openlawlibrary",
"engines": {
"node": ">=16.17.1",
Expand Down Expand Up @@ -126,7 +126,7 @@
}
]
},
"main": "./out/extension",
"main": "./out/extension.js",
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p .",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
function getClientOptions(): LanguageClientOptions {
const config = vscode.workspace.getConfiguration('pygls.client')
const options = {
documentSelector: config.get<any>('documentSelector'),

Check warning on line 211 in .vscode/extensions/pygls-playground/src/extension.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
outputChannel: logger,
connectionOptions: {
maxRestartCount: 0 // don't restart on server failure.
Expand All @@ -218,7 +218,7 @@
return options
}

function startLangServerTCP(addr: number): LanguageClient {

Check warning on line 221 in .vscode/extensions/pygls-playground/src/extension.ts

View workflow job for this annotation

GitHub Actions / build

'startLangServerTCP' is defined but never used
const serverOptions: ServerOptions = () => {
return new Promise((resolve /*, reject */) => {
const clientSocket = new net.Socket();
Expand Down Expand Up @@ -268,22 +268,33 @@
}

/**
* If the user has explicitly provided a src directory use that.
* Otherwise, fallback to the examples/servers directory.
*
* @returns The working directory from which to launch the server
*/
function getCwd(): string {
const config = vscode.workspace.getConfiguration("pygls.server")
const cwd = config.get<string>('cwd')
if (cwd) {
return cwd
let cwd = config.get<string>('cwd')
if (!cwd) {
const message = "Please set a working directory via the `pygls.server.cwd` setting"
logger.error(message)
throw new Error(message)
}

const serverDir = path.resolve(
path.join(__dirname, "..", "..", "servers")
)
return serverDir
// Check for ${workspaceFolder} etc.
const match = cwd.match(/^\${(\w+)}/)
if (match && (match[1] === 'workspaceFolder' || match[1] === 'workspaceRoot')) {
if (!vscode.workspace.workspaceFolders) {
const message = "The 'pygls-playground' extension requires an open workspace"
logger.error(message)
throw new Error(message)
}

// Assume a single workspace...
const workspaceFolder = vscode.workspace.workspaceFolders[0].uri.fsPath
cwd = cwd.replace(match[0], workspaceFolder)
}

return cwd
}

/**
Expand Down
37 changes: 37 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"configurations": [
{
"name": "pygls: Debug Server",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "${config:pygls.server.debugHost}",
"port": "${config:pygls.server.debugPort}"
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
],
"justMyCode": false
},
{
"name": "pygls: Debug Client",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}/.vscode/extensions/pygls-playground",
"--folder-uri=${workspaceRoot}/examples/servers",
],
"outFiles": [
"${workspaceRoot}/.vscode/extensions/pygls-playground/out/**/*.js"
],
"preLaunchTask": {
"type": "npm",
"script": "watch"
},
},
]
}
10 changes: 3 additions & 7 deletions examples/servers/.vscode/settings.json → .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
{
"[plaintext]": {
// Uncomment to enable `textDocument/onTypeFormatting` requests
//"editor.formatOnType": true
// "editor.formatOnType": true
},
// Uncomment to override Python interpreter used.
// "pygls.server.pythonPath": "/path/to/python",
"pygls.server.debug": false,
// "pygls.server.debugHost": "localhost",
// "pygls.server.debugPort": 5678,
"pygls.server.launchScript": "formatting.py",
"pygls.server.launchScript": "formatting.py", // This is relative to `pygls.server.cwd`
"pygls.server.cwd": "${workspaceFolder}/examples/servers",
"pygls.trace.server": "off",
"pygls.client.documentSelector": [
// {
// "scheme": "file",
// "language": "json"
// }
// Uncomment to use code_actions or inlay_hints servers
{
"scheme": "file",
"language": "plaintext"
Expand Down
File renamed without changes.
20 changes: 0 additions & 20 deletions examples/servers/.vscode/launch.json

This file was deleted.

23 changes: 0 additions & 23 deletions examples/vscode-playground/.vscode/launch.json

This file was deleted.

Loading
Loading