This tutorial describes how the define an language server integration for the Eclipse IDE

1. Developing with a language server

The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server. The language server provides language features like auto complete, go to definition, find all references etc. To learn about the language server protocol see https://github.com/Microsoft/language-server-protocol and https://microsoft.github.io/language-server-protocol/specification

LSP4J (Language Server Protocol for Java) is an Eclipse project which provides Java bindings for the Language Server Protocol. The LSP is based on an extended version of JSON RPC v2.0, for which LSP4J provides a Java implementation. Therefore, we are able to use it to create a language server without having to deal with the JSON specifics of the LSP and instead create endpoints for which we are given parameters from the client and return the required actions in object form based on which message our server receives.

The Eclipse LSP4E provides technologies to simplify the integration of language servers into the Eclipse IDE.

1.1. Required dependencies

For a server with Java bindings you need:

  • org.eclipse.lsp4j

  • org.eclipse.lsp4j.jsonrpc

For an Eclipse client you need:

  • org.eclipse.lsp4e

2. Exercise: Dart LanguageServer implementation

In this exercise you will implement a runnable extension that adds Language Server features like auto completion and problem highlighting for the Dart programming language.

The Dart SDK contains a fully fledged implementation of the language server protocol for the Dart language. You can install it by installing at least the Dart SDK 2.2.

2.1. Install the LSP4E project

Use the p2 repository from https://download.eclipse.org/lsp4e/releases/latest/ to install the lsp4e package and its dependencies. Install the package org.eclipse.lsp4j and Language Server Protocol client for Eclipse IDE (Incubation) Source. This will give enough functionality to add the language server features to your plug-in.

2.2. Setting up the language server

Create a new plug-in project. Name it com.vogella.dartlanguageserver. No template is required.

New Plugin Templates

2.2.1. Adding the necessary dependencies

Once the project has then been created, open the MANIFEST.MF file in the META-INF folder of your project.

Click on the Extensions tab to add the necessary extension points.

The list of available extensions will be empty at first. To fix this uncheck the Show only extension points from the required plugins checkbox. This will give you the ability to choose from all available extension points. Filter and choose the extension org.eclipse.core.contenttype.contentTypes from the list and click Finish.

Since you don’t declare the dependency on the required plug-in there will be a pop-up shown.

Missing dependency pop-up

Click Yes.

This will add the missing dependency to your plug-in.

Repeat this process for the extensions

  • org.eclipse.ui.editors

  • org.eclipse.lsp4e.languageServer.

Your list of extensions should now look like this:

All extensions after the language server setup

2.2.2. Define content-type and associate it with generic editor

Now that you added the extension points these need be configured.

First you will need to add a content type. Right Click on org.eclipse.core.contenttype.contentTypes, select New  content-type.

Table 1. ContentType
Field Value Description

id

com.vogella.dartlanguageserver

An id that identifies your contentType for later references.

name

Dart Language Server

Some name for the contentType.

base-type

org.eclipse.core.runtime.text

The base type of the contentType.

file-extensions

dart

The files this contentType should be registered to. In this case *.dart files.

Content Type extension detail

Next you will need an editorContentBinding. Right click on org.eclipse.ui.editors and select New  editorContentBinding.

Fill in the following data:

Table 2. editorContentBinding
Field Value Description

editorTypeId

com.vogella.dartlanguageserver

This is the id of the contentType you created earlier.

editorId

org.eclipse.ui.genericeditor.GenericEditor

This is the id of the Generic Editor.

Extension Element Details for the editors package

This will associate any .dart file with the generic editor.

2.3. Define the language server and associate with your content-type

Now define your language server implementation via the org.eclipse.lsp4e.languageServer extension

If you get the warning "No schema found for the 'org.eclipse.lsp4e.languageserver' extension point", check if you have installed the Language Server Protocol client for Eclipse IDE (Incubation) Source package.
Table 3. Server
Field Value Description

class

com.vogella.dartlanguageserver.DartStreamConnectionProvider

The class which will initialize the language server

id

com.vogella.dartlanguageserver.server

A unique id that identifies your server. Useful if you want to add multiple servers.

label

com.vogella.dartlanguageserver.server

The label for the server

LSP4E Extension Server
The class field points to a class that implements StreamConnectionProvider. You will add that in the next step.

Now associate the defined server with your contentType via the contentTypeMapping property.

Table 4. ContentTypeMapping
Field Value Description

contentType

com.vogella.dartlanguageserver

The contentType you created earlier

id

com.vogella.dartlanguageserver.server

The id of the language server from the step above

LSP4E Extension - contentTypeMapping

2.3.1. Configuring the language server

Now you need to supply the class that handles the lifecycle of the language server, the StreamConnectionProvider.

Create the class com.vogella.dartlanguageserver.DartStreamConnectionProvider. This is the class you referenced in the server extension point above.

package com.vogella.dartlanguageserver;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider;
import org.eclipse.lsp4e.server.StreamConnectionProvider;

public class DartStreamConnectionProvider extends ProcessStreamConnectionProvider implements StreamConnectionProvider{

    public DartStreamConnectionProvider() {
        String dartSdkLocation = "/usr/lib/dart"; (1)

        List<String> commands = new ArrayList<>();
        commands.add(dartSdkLocation + "/bin/dart");
        commands.add(dartSdkLocation + "/bin/snapshots/analysis_server.dart.snapshot");
        commands.add("--lsp"); (2)
        setCommands(commands);
        setWorkingDirectory(System.getProperty("user.dir"));
    }
}
1 The Dart SDK location. This might be different on your OS and depends on the way how you installed the Dart SDK. To find the exact location use the $ which dart command.
2 This tells the Dart analysis server to start in "lsp" mode

2.4. Check the implementation

The resulting plugin.xml should look like the following:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.core.contenttype.contentTypes">
      <content-type
            base-type="org.eclipse.core.runtime.text"
            file-extensions="dart"
            id="com.vogella.dartlanguageserver"
            name="Dart Language Server"
            priority="normal">
      </content-type>
   </extension>
   <extension
         point="org.eclipse.ui.editors">
      <editorContentTypeBinding
            contentTypeId="com.vogella.dartlanguageserver"
            editorId="org.eclipse.ui.genericeditor.GenericEditor">
      </editorContentTypeBinding>
   </extension>
   <extension
         point="org.eclipse.lsp4e.languageServer">
      <server
            class="com.vogella.dartlanguageserver.DartStreamConnectionProvider"
            id="com.vogella.dartlanguageserver.server"
            label="com.vogella.dartlanguageserver.server">
      </server>
      <contentTypeMapping
            contentType="com.vogella.dartlanguageserver"
            id="com.vogella.dartlanguageserver.server">
      </contentTypeMapping>
   </extension>
</plugin>

2.4.1. Testing the language server

If everything went well, you should now be able to get content assist and problem highlighting in your eclipse runtime for dart files.

To test this, right click on your project and select Run As  1. Eclipse Application.

Ensure your run configuration also includes org.eclipse.ui.genericeditor. One way of ensuring this is to add it as Dependency to your com.vogella.dartlanguageserver plug-in. Alternatively, you can modify the runtime configuration.

Create a new project in the newly started instance and add a file named test.dart in the project. Open it and write Dart code.

void main() {
  print('Hello, World!');
}
If the file doesn’t open in the Generic Editor, you don’t get code completion or no problem highlighting, check the console log in the host eclipse instance for errors.

3. Exercise: Dart Syntax Highlighting

The Eclipse project TM4E adds syntax highlighting capabilities to the Eclipse IDE. Using special "grammar" files that define the colors and words used by your language it can display code with the proper syntax highlight.

3.1. Getting Started using TM4E

The easiest way to get started is by adding the update site of the project: https://download.eclipse.org/tm4e/snapshots/. Add it to your eclipse installation center and install the following plugins:

  • TextMate Core

  • TextMate Core Developer Resources

3.2. Configuring the Extensions

Open the MANIFEST.MF file in the META-INF folder. Navigate to the Extensions tab and click on Add. Again, uncheck Show only extension points from the required plugins.

Add the following extension points:

  • org.eclipse.tm4e.registry.grammars

  • org.eclipse.tm4e.languageconfiguration.languageConfigurations

4. Eclipse Language Server