Skip to main content

Ralsina.Me — Roberto Alsina's website

Extending Marave

Mar­ave is a text ed­i­tor. If there's one thing that's true of most text ed­i­tors, it's this: they lack the ex­act fea­tures you need.

So, the so­lu­tion, in the an­cient tra­di­tion of Emacs and Vim is... make it ex­ten­si­ble.

I am a big fan of pro­grams that can be ex­tend­ed by users.

So... here's the anato­my of a Mar­ave plug­in as it stands right now on SVN trunk, which of course can change any minute.

Creating a plugin

You just need to cre­ate a .py file in the plug­ins fold­er.

Here's the most ba­sic plug­in, which does noth­ing:

# -*- coding: utf-8 -*-

from plugins import Plugin
class Smarty(Plugin):
    name='smarty'
    shortcut='Ctrl+.'
    description='Smart quote and dash replacement'
    mode="qBde"

De­fault val­ues for any­thing con­fig­urable (in this case, "mod­e") is just added to the class.

The manda­to­ry field­s:

  • short­­­cut: a key­board short­­­cut that trig­gers this plug­in

  • name: a short name

  • de­scrip­­tion: a one-­­line de­scrip­­tion of what it does

What does it do? It adds the plug­in to the plug­in list in the prefs di­alog, and you can open its con­fig­u­ra­tion di­alog, where you can change the short­cut:

maraveplugin1

If you en­able this plug­in, when­ev­er the short­cut is used the "run" method of the plug­in is called.

Making the Plugin Configurable

This plug­in sup­ports dif­fer­ent modes of op­er­a­tion. To make this reach­able to the user, you need to im­ple­ment a few ex­tra meth­od­s.

The ad­d­Con­fig­Wid­gets method takes a di­a­log ar­gu­ment and adds what­ev­er you want there:

@classmethod
def addConfigWidgets(self, dialog):
    print 'Adding widgets to smarty config'
    l=dialog.ui.layout
    self.q=QtGui.QCheckBox(dialog.tr('Replace normal quotes'))
    if 'q' in self.mode:
        self.q.setChecked(True)
    self.b=QtGui.QCheckBox(dialog.tr('Replace backtick-style quotes (` and ``)'))
    if 'B' in self.mode:
        self.b.setChecked(True)
    self.d=QtGui.QCheckBox(dialog.tr('Replace -- by en-dash, --- by em-dash'))
    if 'd' in self.mode:
        self.d.setChecked(True)
    self.e=QtGui.QCheckBox(dialog.tr('Replace ellipses'))
    if 'e' in self.mode:
        self.e.setChecked(True)
    l.addWidget(self.q)
    l.addWidget(self.b)
    l.addWidget(self.d)
    l.addWidget(self.e)

And then the con­fig di­a­log will look like this:

maraveplugin2

But then you need to save those op­tions some­where, which you do reim­ple­ment­ing save­Con­fig:

@classmethod
def saveConfig(self, dialog):

    self.shortcut=unicode(dialog.ui.shortcut.text())
    self.settings.setValue('plugin-'+self.name+'-shortcut', self.shortcut)

    newmode=""
    if self.q.isChecked():
        newmode+='q'
    if self.b.isChecked():
        newmode+='B'
    if self.d.isChecked():
        newmode+='d'
    if self.e.isChecked():
        newmode+='e'
    self.mode=newmode

    self.settings.setValue('plugin-smarty-mode',self.mode)
    self.settings.sync()

And you need to load those set­tings and put them in your class, too:

@classmethod
def loadConfig(self):
    print 'SMARTY loadconfig', self.settings
    if self.settings:
        sc=self.settings.value('plugin-'+self.name+'-shortcut')
        if sc.isValid():
            self.shortcut=unicode(sc.toString())
        mode=self.settings.value('plugin-smarty-mode')
        if mode.isValid():
            self.mode=unicode(mode.toString())

Making it Work

And yes, you need to make it do some­thing use­ful. The plug­in has ac­cess to a "clien­t" which is Mar­ave's main win­dow. Ev­ery­thing is avail­able there, some­where ;-)

def run(self):
    print 'running smarty plugin'
    text=unicode(self.client.editor.toPlainText()).splitlines()
    prog=QtGui.QProgressDialog(self.client.tr("Applying smarty"),
                               self.client.tr("Cancel"),
                               0,len(text),
                               self.client)
    prog.show()
    output=[]
    for i,l in enumerate(text):
        output.append(unescape(smartyPants(l,self.mode)))
        prog.setValue(i)
        QtGui.QApplication.instance().processEvents()
    prog.hide()
    self.client.editor.setPlainText('\n'.join(output))

And there it is, if you en­able the smar­ty plug­in, you can "fix" your quotes, dash­es and el­lip­sis with a key com­bi­na­tion :-)

Full source code here: http://­code.­google.­com/p/­mar­ave/­source/browse/trunk­/­mar­ave/­plu­g­in­s/s­mar­ty.py

Still to be done: oth­er ways to in­te­grate plug­ins in­to the UI, but­ton­s, pan­el­s, etc.


Contents © 2000-2023 Roberto Alsina