Builder Plugins – Part II

Previously, Builder Plugins, Part I. Read this if you haven’t.

Now that we’ve learned the mechanics of creating a plugin, let’s look at another plugin interface, IdeWorkbenchAddin. This interface allows us to extend the IdeWorkbench. An IdeWorkbench is the toplevel window for a given project. Since Builder supports having more than one project open at a time (each in a given workbench window), this is the interface you would use for extensions that are per-project.

the workbench window

The workbench window has an important property. The IdeWorkbench:context. This is the IdeContext. Each loaded project has an IdeContext. This is the primary data structure that provides access to your Version Control System, Build System, Device Manager, and many other components.

The two important virtual functions in the IdeWorkbenchAddin interface are IdeWorkbenchAddin::load and IdeWorkbenchAddin::unload. These provide an IdeWorkbench as a parameter, for which you can use to your hearts content. IdeWorkbenchAddin::unload() should reverse anything that happened in IdeWorkbenchAddin::load().

The other virtual functions are optional, and can be used to allow your IdeWorkbenchAddin to perform custom actions upon opening URIs and such. I’m sure we’ll add more as we go.

Anyway, let’s create a sample IdeWorkbenchAddin that prints some information about our loaded project.

# my_plugin.py

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

class MyWorkbenchAddin(GObject.Object, Ide.WorkbenchAddin):
    def do_load(self, workbench):
        self.workbench = workbench

        context = workbench.props.context
        vcs = context.props.vcs
        build_system = context.props.build_system

        print("Version Control System is:", repr(vcs))
        print("Build System is:", repr(build_system))

    def do_unload(self, workbench):
        self.workbench = None

Use the same my_plugin.plugin found in Part I.

Running Builder should result in something like this on the command line.

Version Control System is: <__gi__.IdeGitVcs object at 0x7fffbd8de438 (IdeGitVcs at 0x1caaee0)>
Build System is: <__gi__.IdeAutotoolsBuildSystem object at 0x7fffbd8de798 (IdeAutotoolsBuildSystem at 0x1d00890)>

You can see that my project uses Git for Version Control, and Autotools for the build system. Nothing too spectacular here, so now we’ll move on to something a bit more complex.

perspectives See each of the icons on the left of the workbench? Those are what we call perspectives. Currently, we only have two perspectives. One for the editor, and one for preferences. I’m sure you can imagine a bunch of new perspectives. Bugzilla, git, debugger, profiler, database browser, and designer all come to mind.

I should mention that I’m not sure whether or not we’ll keep the perspective bar like this. It’s been there since some of the earliest designs, but we may opt for something slightly different.

Like many of the other extension points in Builder, IdePerspective is an interface you can implement in your library. However, you need to add it to the workbench using IdeWorkbench.add_perspective(). As always, you should remove it when you unload your plugin, using IdeWorkbench.remove_perspective().

Lets create a Hello World perspective.

# my_plugin.py

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

class MyWorkbenchAddin(GObject.Object, Ide.WorkbenchAddin):
    def do_load(self, workbench):
        self.perspective = HelloPerspective(visible=True)
        workbench.add_perspective(self.perspective)

    def do_unload(self, workbench):
        workbench.remove_perspective(self.perspective)
        self.perspective = None

class HelloPerspective(Gtk.Box, Ide.Perspective):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        label = Gtk.Label(label="Hello, World!",
                          expand=True,
                          visible=True)
        self.add(label)

        self.titlebar = Ide.WorkbenchHeaderBar(visible=True)

    def do_get_id(self):
        return 'hello-world'

    def do_get_title(self):
        return 'Hello'

    def do_get_priority(self):
        return 10000

    def do_get_icon_name(self):
        return 'image-missing'

    def do_get_titlebar(self):
        return self.titlebar

Lets run Builder and see what happens!

Screenshot from 2016-01-21 15-48-43

More next time, same bat channel.