Saturday, September 30, 2006

» Scripting Gedit +

Gedit allows you to write python scripts which interface with its backend (and frontend via pygtk). This is very cool, for reasons obvious to VIM and Emacs users. You can write your own plugins to manipulate the document you are editing in many useful ways.

Well I was using various external tools to run my various scripts for test purposes (the External Tools plugin is itself written in python!). So I'd bind F5 to ruby, F6 to python and F10 to perl. Then, depending on the script I was editing, I'd press the corresponding accel key to run it. But I realized that I could just write a plugin that would run any script according to its bang line. The following is the plugin I came up with (place it in ~/.gnome2/gedit/plugins):

First is the plugin definition file (named script_runner.gedit-plugin):

[Gedit Plugin]
Name=Script Runner Plugin
Description=This plugin runs scripts by reading the bang line.
Authors=Jordan Callicoat <>\nJonathan-Marc Lapointe
Copyright=Copyright © Jordan Callicoat, 2006

Then is the actual python script file (named

#  Script Runner plugin
# coding: utf-8
# Copyright © 2006 Jordan Callicoat
# Copyright © 2008 Jonathan-Marc Lapointe
# Released under the python license.

import re
import os
import gtk
import gedit
from externaltools.functions import capture_menu_action
from externaltools.ElementTree import Element

class RunScriptPlugin(gedit.Plugin):
A simple plugin that runs the current document
in the interpreter specified by the bang line

def run_document(self, action, window):
Just Do It!
# read in the first line of the buffer...
buff = window.get_active_view().get_buffer()
siter = buff.get_iter_at_line_offset(0,0)
eiter = buff.get_iter_at_line_offset(1,0)
data = buff.get_text(siter, eiter)
# now check if it contains a bang line...
if data:
text = re.match(r'^#!(.*)$', data)
if text: # it does...
text =
# extract a label (for use in the output
# panel) from the bang line...
label = os.path.basename(text).split(' ', 1)
if label[0].lower() == 'env':
label = label[1]
label = label[0]
# build an ElementTree Element to feed capture_menu_action...
elem = Element('tool')
elem.command = text = label # .title()
elem.input = 'document'
elem.output = 'output-panel'
# now run the script!
capture_menu_action(None, window, elem)

def activate(self, window):
Setup stuff
actions = [
('Run', gtk.STOCK_EXECUTE, 'Run Script', 'F5', 'Run Script', self.run_document),
# store per window data in the window object
windowdata = {}
window.set_data('RunScriptPluginWindowDataKey', windowdata)
windowdata['action_group'] = gtk.ActionGroup('GeditRunScriptPluginActions')
windowdata['action_group'].add_actions(actions, window)
manager = window.get_ui_manager()
manager.insert_action_group(windowdata['action_group'], -1)
ui_str = """
<menubar name="MenuBar">
<menu name="ToolsMenu" action="Tools">
<placeholder name="ToolsOps_3">
<menuitem name="Run" action="Run"/>
windowdata['ui_id'] = manager.add_ui_from_string(ui_str)
window.set_data('RunScriptPluginInfo', windowdata)

def deactivate(self, window):
Teardown stuff
windowdata = window.get_data('RunScriptPluginWindowDataKey')
manager = window.get_ui_manager()

def update_ui(self, window):
UI Callback
view = window.get_active_view()
windowdata = window.get_data('RunScriptPluginWindowDataKey')
windowdata['action_group'].set_sensitive(bool(view)) # and view.get_editable()))

After you add these files, you need to restart Gedit. Then you go to Preferences -> Plugins tab -> check the Script Runner Plugin option, and you're set. Now pressing F5 will automagically run any script with a bang line. Cool stuff! :)

Note: The External Tools plugin needs to be enabled for this script to work! Updated to work with newer gedit versions, thanks Jonathan.

Labels: , ,


Blogger jml75 said...

Very Nice but it does not work anymore with newer versions of gedit.

I'm trying to use it with Gnome 2.22.1.

I modded it a bit, I feel I'm getting closer but it still does not work.

Could you help me please?

May 24, 2008 at 9:00 AM

Blogger MonkeeSage said...

I think we got it sorted out now. Thanks for your help. :)
May 25, 2008 at 4:07 PM


Post a Comment

<< Home