Skip to content

Support no-code language server integration #158076

Open
@remcohaszing

Description

@remcohaszing

I created a VSCode extension that integrates a language server. This is pretty much a textbook example extension.

import {workspace} from 'vscode'
import {LanguageClient, TransportKind} from 'vscode-languageclient/node.js'

let client

export async function activate(context) {
  const run = {
    module: context.asAbsolutePath('out/remark-language-server.js'),
    transport: TransportKind.ipc,
  }

  const serverOptions = {
    run,
    debug: {...run, options: {execArgv: ['--inspect=6009']}}
  }

  const clientOptions = {
    documentSelector: [{scheme: 'file', language: 'markdown'}],
    synchronize: {
      fileEvents: [
        workspace.createFileSystemWatcher(
          '**/.remark{ignore,rc,rc.cjs,rc.js,rc.json,rc.mjs,rc.yaml,rc.yml}'
        ),
        workspace.createFileSystemWatcher('**/package.json')
      ]
    }
  }

  client = new LanguageClient('remark', serverOptions, clientOptions)

  await client.start()
}

export async function deactivate() {
  if (client) {
    await client.stop()
  }
}

All of this is boilerplate with some configuration options. In addition to handling the language server, the extension developer is responsible for proper teardown and building the extension. Also this small extension adds ~350kB of minified JavaScript to the bundle.

It would be nice if language server integrations could be specified in package.json, replacing the extension bundle. This way developers can focus solely on the language server functionality, and extension size can be decreased.

{
  "name": "vscode-remark",
  "displayName": "remark",

  // This line would no longer be needed
  // "main": "out/extension.js",

  "contributes": {
    "languageServer": {
      // Defaults to displayName
      // "name": "remark",
      "serverOptions": {
        "run": {
          "module": "out/remark-language-server.js",
          "transport": "ipc"
        },
        // Inherits properties from run
        "debug": {
          "options": {
            "execArgv": [
              "--inspect=6009"
            ]
          }
        }
      },
      "clientOptions": {
        "documentSelector": [
          {
            "scheme": "file",
            "language": "markdown"
          }
        ],
        "synchronize": {
          "fileEvents": [
            "**/package.json",
            "**/.remark{ignore,rc,rc.cjs,rc.js,rc.json,rc.mjs,rc.yaml,rc.yml}"
          ]
        }
      }
    },
    //
  },
}

Of course there are many more options that are unused here. Some functionality still requires extensions to manually initialize a client. Each accepted option should be considered separately to be supported this way.

Metadata

Metadata

Assignees

Labels

apifeature-requestRequest for new features or functionality

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions