How can I develop an Extension for Code. I want to recreate atom's pigments package into Code.
1 Answer
This question is definitely not as trivial as one would think, as there's virtually no documentation and you have to feel your way around the Code sources itself.
NOTE: In this example I'll demonstrate the bare minimum in Vala that compiles, links dynamically against the Code core library and loads into Code with no problems. There is definitely some room for improvements here, as I'm only a beginner when it comes to Meson and Vala things.
The preparations
First thing you have to do is to grab a source release from here. Download any required dependencies listed in the README.md, then build it.
Now create your plugin project as usual, with the directory structure as follows:
.
├── src/
├── lib/
└── vapi/
Now we need codecore.vapi
and codecore.h
for the built library libcodecore
.
Go to your <directory with editor's source>/build/src
and copy over the codecore.vapi
and codecore.h
into your project's vapi/
directory.
Now copy over the libcodecore.so.0.0
from the same directory into your project's lib/
directory, but rename it to libcodecore.so
instead.
Next, create a meson.build
with the following content:
project('helloworldplugin', 'vala', 'c')
module_name = 'helloworldplugin'
cp = find_program('cp')
vapi_dir = join_paths(meson.current_source_dir(), 'vapi')
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
libcodecore = meson.get_compiler('c').find_library('codecore', dirs: join_paths(meson.current_source_dir(), 'lib'))
shared_library(
meson.project_name(),
'src/helloworldplugin.vala',
dependencies: [
dependency('glib-2.0'),
dependency('gobject-2.0'),
dependency('gtk+-3.0'),
dependency('granite'),
dependency('gtksourceview-3.0'),
dependency('libpeas-1.0'),
libcodecore
],
include_directories: include_directories('vapi'),
vala_args: ['--pkg=codecore'], # https://github.com/mesonbuild/meson/issues/2103
)
custom_target(
module_name + '.plugin',
input: join_paths('src', module_name + '.plugin'),
output: module_name + '.plugin',
command: [cp, '@INPUT@', join_paths(meson.current_build_dir(), '@OUTPUT@')],
install: true,
install_dir: ''
)
At this point we have everything we need to start writing actual plugin.
The plugin
Create a file called helloworldplugin.vala
in your project's src/
directory, with the following contents:
namespace HelloWorld {
public class HelloWorldPlugin : Peas.ExtensionBase, Peas.Activatable {
// Assigned by Code at runtime, has to be casted to plugin interface object below.
public Object object { owned get; construct; }
Scratch.Services.Interface plugins;
Scratch.MainWindow main_window;
public void update_state() { return; }
public void activate()
{
plugins = (Scratch.Services.Interface)object;
plugins.hook_window.connect((window) => {
this.main_window = window;
});
print("hello, world - activate\n");
}
public void deactivate()
{
print("hello, world - deactivate\n");
}
}
}
// Gets picked up by libpeas engine.
[ModuleInit]
public void peas_register_types(GLib.TypeModule module) {
var objmodule = module as Peas.ObjectModule;
objmodule.register_extension_type(typeof(Peas.Activatable),
typeof(HelloWorld.HelloWorldPlugin));
}
Now we need some plugin metadata. Create a file and name it helloworldplugin.plugin
with the following contents:
[Plugin]
Name=Hello world plugin
Module=helloworldplugin
Loader=C
IAge=2
Description=Bare-bones hello world plugin
Authors=Someone
Copyright=Nope
Website=https://your.url.here/
Note that Module
entry value needs to match your what's between lib
and .so
in the output file that we'll have after this step.
The build and installation
At last! We can build the project. Go to the project's root, execute the following command: meson build && cd build && ninja
.
You'll end up inside the build
directory created by Meson.
Code loads its plugins from /usr/lib/x86_64-linux-gnu/io.elementary.code/plugins/
, which is only writeable as root. I am not aware of any other directories Code looks for to load plugins from. I would love for someone to prove me wrong on this, though.
All we have to do now is to create a directory called helloworldplugin
in the above- mentioned directory, copy over the helloworldplugin.plugin
and helloworldplugin.so
into that created directory, and we're done. It needs to be done with root privileges:
sudo mkdir /usr/lib/x86_64-linux-gnu/io.elementary.code/plugins/helloworldplugin
sudo cp helloworldplugin.plugin /usr/lib/x86_64-linux-gnu/io.elementary.code/plugins/helloworldplugin/
sudo cp helloworldplugin.so /usr/lib/x86_64-linux-gnu/io.elementary.code/plugins/helloworldplugin/
The results
To see the results of our work, you need to launch Code from the command line - io.elementary.code
is the command.
Now go to Preferences -> Extensions
and toggle your plugin on/off. Console output should be similar to this:
hello, world - activate
hello, world - deactivate
Remarks
If you want to spare yourself the typing and get straight to the meat of it, here's the GitHub repository
-
Awesome! Thanks for the detailed reply. I will try and feel my way around code. Appreciate it! Aug 10, 2019 at 3:36