In this article, we’ll see how to write plugins for Gedit. Since plugin development is easy in Python, I’m planning to explain this using Python.
When the first caveman programmer chiseled the first program on the walls of the first cave computer, it was program to paint the string “Hello, world” in Antelope pictures. Roman programming textbooks began with the “Salut, Mundi” program. I don’t know what happens to people who break with this tradition, but I think it’s safer not to find out. So we’ll also deal only with HelloWorld in our first plugin.
This plugin is going to do two things. One is to add the string “HelloWorld ” at the cursor position. The next is to convert all “Hello” in the program to “World”. A neat tutorial to write python plugins is can be found at live.gnome.org. Though you can skip that tutorial for now since I’ve explained most of the things one need to know to write this plugin. But i suggest you read that tutorial soon.
Some of the paths you need to know for writing a plugin.
Path | Details |
---|---|
/usr/lib/gedit-2/plugins/ | System-wide plugins directory |
~/.gnome2/gedit/plugins/ | User Plugins directory |
/usr/share/gedit-2/ | Data needed for system-wide plugins. |
~/.gconf/apps/gedit-2/ | Gedit configuration. Can be modified using gconf-editor. |
/usr/share/gtk-doc/html/gedit | gedit Reference Manual |
Every python plugin needs at least two files. Let us name our plugin as “frisco”. So we should have two files namely, frisco.gedit-plugin and frisco.py
Let’s start with the contents of frisco.gedit-plugin.
[Gedit Plugin]
Loader=python
Module=frisco
IAge=2
Name=HelloWord
Description=A HelloWorld plugin for Gedit.
Authors=Harishankaran K <sp2hari@gmail.com>
Copyright=Copyright © sp2hari
Website=http://www.sp2hari.com
The contents of this file is almost same for all the plugins. The module, name and description will change for different plugins. If your plugin has the python file frisco.py, then the modulde is frisco.
Note :: We don’t specify the extension in the module name.
The .gedit-plugin file is done now. Next let’s move on to frisco.py.
#!/usr/bin/python
import gedit
class HelloWorldPlugin(gedit.Plugin):
def __init__(self):
print "Plugin loaded"
def activate(self, window):
print "Plugin activated"
def deactivate(self, window):
print "Plugin deactivated"
def update_ui(self, window):
pass
This file, frisco.py derives one class from the Gedit.plugin and defines activate, deactivate and update_ui. activate() is called when the plugin is activated. Similarly deactivate() is called when the plugin is deactivated. We will check how our plugin works now.
Run gedit from terminal and check whether your plugin is listed in the plugins list.
You can see that the details you provided in frisco.gedit-plugin can be viewed in the About Plugin and the Credits.
Now enable the plugin and look at shell prompt. You will see the print statements being execute when we activate and deactivate the plugin. :). Wow, our first plugin is ready to add more spice. 🙂
Note:: If you get an error saying
WARNING **: Cannot load Python plugin ‘HelloWord’ since file ‘frisco’ cannot be read.
WARNING **: Error activating plugin ‘HelloWord’
Then the file frisco.py is not present in your plugins directory or the python file has an error. Fix the code and try again. You will get the output as shown below.
The output for the above plugin in the shell when the plugin is activated and deactivated for a few times will be like
hari@hari-laptop:~$ gedit
Plugin loaded
Plugin activated
Plugin deactivated
Plugin activated
Plugin deactivated
Plugin activated
Plugin deactivated
Plugin activated
Now we have to add functionality to this plugin. A good practice while coding plugin is the create a separate ‘Helper’ Class which will control the window and do all useful actions. It’ll be called once in the main class.
So we will modify the HelloWorldPlugin class as follows
#!/usr/bin/python
import gedit
class HelloWorld(gedit.Plugin):
def __init__(self):
gedit.Plugin.__init__(self)
self._instances = {}
def activate(self, window):
self._instances[window] = HelloWorldHelper(self, window)
def deactivate(self, window):
self._instances[window].deactivate()
del self._instances[window]
def update_ui(self, window):
self._instances[window].update_ui()
The code for the HelloWorldHelper class will be
class HelloWorldHelper:
def __init__(self, plugin, window):
print "Plugin created for", window
self._window = window
self._plugin = plugin
def deactivate(self):
print "Plugin stopped for", self._window
self._window = None
self._plugin = None
def update_ui(self):
# Called whenever the window has been updated (active tab
# changed, etc.)
print "Plugin update for", self._window
When you run gedit from terminal, now, it will print more details like the Gedit window object. A sample run for the above code is given below
hari@hari-laptop:~$ gedit
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin update for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin update for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin stopped for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Plugin created for <gedit.Window object at 0x8521504 (GeditWindow at 0x816e000)>
Hereafter there is no need to change the HelloWorldPlugin class. So we’ll work only on the HelloWorldHelper class. We will define a ui_str which will enable us to add a menuitem in the Tools menu.
We will define the ui_str as follows
import gtk
ui_str = """<ui>
<menubar name="MenuBar">
<menu name="ToolsMenu" action="Tools">
<placeholder name="ToolsOps_2">
<menuitem name="Insert HelloWorld" action="InsertHelloWorld"/>
<menuitem name="Change Hello to World" action="ChangeHellotoWorld"/>
</placeholder>
</menu>
</menubar>
</ui>
"""
The activate, deactivate and update ui functions for the HelloWorldHelper Class are modified as follows
def __init__(self, plugin, window):
self._window = window
self._plugin = plugin
# Insert menu items
self._insert_menu()
def deactivate(self):
self._window = None
self._plugin = None
self._remove_menu()
def update_ui(self):
# Called whenever the window has been updated (active tab
# changed, etc.)
self._action_group.set_sensitive(self._window.get_active_document() != None)
Now we need to write the method insert_menu which will register the callbacks for the actions like inserting hello world and changing hello to world.
The insert_menu function is defined as followed. If you know gtk or pygtk then it’ll be easy for you to understand that code. I’ll advise you to read the basics of pygtk if you plan to write your own plugin.
def _insert_menu(self):
# Get the GtkUIManager
manager = self._window.get_ui_manager()
# Create a new action group
self._action_group = gtk.ActionGroup("ExamplePyPluginActions")
self._action_group.add_actions([("InsertHelloWorld", None, _("Insert HelloWorld"),
None, _("Insert HelloWorld"),
self._inserthelloworld)])
self._action_group.add_actions([("ChangeHellotoWorld", None, _("Change Hello to World"),
None, _("Change Hello to World"),
self._hellotoworld)])
# Insert the action group
manager.insert_action_group(self._action_group, -1)
# Merge the UI
self._ui_id = manager.add_ui_from_string(ui_str)
def _remove_menu(self):
# Get the GtkUIManager
manager = self._window.get_ui_manager()
# Remove the ui
manager.remove_ui(self._ui_id)
# Remove the action group
manager.remove_action_group(self._action_group)
# Make sure the manager updates
manager.ensure_update()
Now we are all set the two final functions which will do the required actions. These are defined in the helper class as follows
def _hellotoworld(self, action):
doc = self._window.get_active_document();
if not doc:
return
doc.replace_all("Hello", "World", 0);
def _inserthelloworld(self, action):
doc = self._window.get_active_document();
if not doc:
print "Noe";
return;
doc.insert_at_cursor("HelloWorld")
Well, that’s all. Your first plugin is up and running now 🙂 🙂
The python files used in this example can be downloaded here.
Pingback: Python:gedit plugin development in python – IT Sprite