Support new editors

Important

This page requires some knowledge about Eclipse RCP development and Eclipse Extension Points.

How editors are handled by the plug-in

The Discord Rich Presence for Eclipse IDE plug-in shows on Discord information extracted from the currently active editor. In order to gather these information, it proceeds as depicted in the following sequence diagram:

Sequence diagram showing how a RichPresence is created from active editor

Basically:

  1. The plug-in is notified each time a new part is opened.
  2. If the part is an instance of IEditorPart then we get its IEditorInput (which represents the underlying element being edited).
  3. This IEditorInput is broadcasted to an instance of EditorInputRichPresence, an interface defined by this plug-in.
  4. The EditorInputRichPresence instance turns the IEditorInput into a RichPresence.
  5. The RichPresence is then shown on Discord through a proxy.

Most of this stuff is managed internally so you don’t have to bother with it. The only thing you’ll have to do is to register a new EditorInputRichPresence (see the Adapt a new IEditorInput section below).

Editors supported out of the box

By default, almost all text-based editors should be taken into account. More specifically, all the editors which input is an instance of one of the following classes are handled:

Adapt a new IEditorInput

Provide a dedicated extension

You can provide an adapter for a given IEditorInput by contributing to the fr.kazejiyu.discord.rpc.integration.editor_input_adapter extension point. You’ll have to provide a class that implements the EditorInputRichPresence interface.

This interface is defined as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
 * Extracts a RichPresence from an IEditorInput.
 *
 * This interface should be implemented by clients who aim to define
 * the information shown in Discord for their own editor.
 */
public interface EditorInputRichPresence extends Comparable<EditorInputRichPresence> {

    /**
     * Helps to choose an adapter over another when several ones
     * are registered for the same {@code IEditorInput}.
     *
     * The higher the priority, the more the adapter will be favored.
     *
     * For instance, given two adapters registering themselves for inputs of type
     * FileEditorInput and which priorities are 0 and 1, then the adapter
     * of priority 1 will be chosen to handle the input.
     *
     * Built-in adapters have a priority of 0. Hence, giving a higher priority
     * ensures that the adapter will be preferred over default ones. This allows
     * to dynamically override other adapters if needed.
     *
     * It is advised to only choose tens, such as 10 or 20, instead of digits
     * so that it is easier to add new adapters later if needed.
     *
     * @return the priority associated with this adapter.
     */
    int getPriority();

    /**
     * Returns the class of the input expected as an argument of createRichPresence(GlobalPreferences, IEditorInput)}.
     * @return the class of the input expected as an argument of createRichPresence(GlobalPreferences, IEditorInput)}
     */
    Class<? extends IEditorInput> getExpectedEditorInputClass();

    /**
     * Creates the Rich Presence information to send to Discord.
     *
     * Important: this method may be called several times in a row with the same editor input.
     *
     * @param preferences
     *             User's preferences regarding the information to show in Discord.
     *             Must not be null.
     * @param input
     *             The input of the active editor.
     *             Must satisfy getExpectedEditorInputClass().isInstance(input) == true.
     *
     * @return the information to show in Discord if the input can be handled
     */
    Optional<RichPresence> createRichPresence(GlobalPreferences preferences, IEditorInput input);
}

As you can see, you have to implement 3 different methods. Their use is detailed in the JavaDoc, but I believe that the third one may benefit from additional hints.

Manage user’s preferences

First of all, the createRichPresence is responsible of actually creating a Rich Presence that will be shown on Discord from an editor’s input. Its first parameter, preferences, is here because it is your responsibility to ensure that the information shown in Discord follow user’s preferences. The GlobalPreferences class represents the preferences set by the user at global scope. If you manage to find the IProject associated to the IEditorInput you use the following snippet to get the applicable preferences (either project or global scope):

UserPreferences applicablePreferences = preferences.getApplicablePreferencesFor(project);

Create a new RichPresence

The ImmutableRichPresence class allows you to create a new Rich Presence easily. See the official RPC documentation for a description of how available fields are shown on Discord.

Hint

If no Rich Presence can be created from the given IEditorInput (for instance in the case where the input does not provide enough information) then you should not throw any exception but rather return Optional.empty() instead.

Example

The following snippet is extracted from DefaultFileEditorInputRichPresence, a built-in adapter, and shows how a RichPresence is created from an editor input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Override
public Optional<RichPresence> createRichPresence(GlobalPreferences preferences, IEditorInput input) {
    if (!(input instanceof IFileEditorInput)) {
        throw new IllegalArgumentException("input must be an instance of " + IFileEditorInput.class);
    }
    IFileEditorInput fileInput = (IFileEditorInput) input;
    IFile file = fileInput.getFile();
    IProject project = file.getProject();

    UserPreferences applicablePreferences = preferences.getApplicablePreferencesFor(project);

    ImmutableRichPresence presence = new ImmutableRichPresence()
            .withProject(project)
            .withDetails(detailsOf(applicablePreferences, file))
            .withState(stateOf(applicablePreferences, project))
            .withLanguage(languageOf(applicablePreferences, file))
            .withLargeImageText(largeImageTextOf(applicablePreferences, file));

    return Optional.of(presence);
}