Builder Plugins – Part I

The time to start writing plugins for Builder is here!

While the API of LibIDE may churn a bit, now is a good time to get started on your plugin of choice. Things are easier than ever and we hope to continue trending in that direction.

We support writing plugins in a variety of languages. Currently, C, Vala, and Python 3 are all supported in Builder.You can find examples of all of these in the plugins/ directory.

We use libpeas for our plugin support. That means the process for creating a plugin in Builder is quite similar to Gedit, Rythmbox, Eog, and others.

I’m going to use Python 3 as our language of choice for examples due to the succinctness.

Create a .plugin description

The first step in our plugin is to create a plugin description file. The convention we use for this is module-name.plugin.

[Plugin]
Name=Hello World
Description=A sample hello world plugin
Authors=Example 
Copyright=Copyright © 2016 Example

Loader=python3
Module=my_plugin

The stuff at the top is your basic title, description, and attribution.

The two lines at the bottom tell us what plugin loader to use, and the name of the module to load. In this case, we want to use the python3 loader. Omitting this line would default to the C loader, which can load a shared library using an equivalent to dlopen().

The Module, in this case, is our Python 3 module. If we were doing this in C or Vala, it would be the name of the shared library, omitting the “lib” prefix and “.so” suffix.

Create a plugin Python module

Lets create our python module now. The following will create an IdeApplicationAddin. An IdeApplicationAddin allows you to extend the IdeApplication object. There is only ever one IdeApplication per-process, so this is an excellent place to put “singleton” type code.

# my_plugin.py

from gi.repository import GObject
from gi.repository import Ide

# Ide.ApplicationAddin interface requires a GObject, so we
# inherit from GObject.Object. Ide.ApplicationAddin is an
# interface and it has two override'able methods. do_load()
# and do_unload(). Each take the application instance as a
# parameter.
class MyAppAddin(GObject.Object, Ide.ApplicationAddin):
    def do_load(self, app):
        print("Hello, World!")

        # If you'd like to access this instance like a
        # singleton from other extensions in your plugin,
        # then you might want to give yourself access to
        # the MyAppAddin instance.
        #
        # Doing the following will allow you to use
        # "MyAppAddin.instance" as your singleton.
        MyAppAddin.instance = self

    def do_unload(self, app):
        # Unload our singleton
        MyAppAddin.instance = None

That’s it! Put my_plugin.plugin and my_plugin.py in ~/.local/share/gnome-builder/plugins and restart Builder.

You should see your plugin in the Extensions section of the Preferences perspective.

hello-world

You can imagine lots of things you might want to do only once per-process. Setup a DBus service, manage compiler tooling, provide access to an external web service, you name it.

In my next post, we’ll take things a bit deeper now that we have the machanics of creating a new plugin.