pymacs! :-)

François Pinard pinard at
Sat Sep 8 03:25:19 CEST 2001

[Paul Winkler]

> Very much so! I love emacs, but there is a lot I can do in python that
> I haven't a clue how to do in emacs lisp. (well, almost anything!)

It goes without saying that Pymacs is not going to be useful, if it
requires its users to have a deep knowledge of both Emacs LISP and Python.
Brian McErlean and I consider that Python scripting as the main goal for
Pymacs.  Hopefully, the Pymacs documentation will contain a few examples
meant for Python users having a limited experience with Emacs.

> For example, let's say I have a a module, let's call it,
> containing this simple python function:

> def break_on_whitespace(some_string):
> 	"""Yes, it's trivial."""
> 	words = some_string.split()
> 	return '\n'.join(words)

> Now I want to tell Emacs about this function so that I can call it on
> a region of text and replace the region with the result of the
> call.  And bind this action to a key, of course.

This is an interesting exercise.  Before diving into it, it is clear that
the Emacs buffer should be handled in some way.  If this is not on the
lisp side, it has to be on the Python side, but we cannot escape handling
the buffer.  So, there is an equilibrium in the work to do for the user,
that could be displaced towards LISP or towards Python.

Let's seek a solution which requires less LISP code, at the expense of
more Python code.  This might be the easiest for one who is a Python user
before a LISP writer.  For one, I would probably manage so the LISP side
transmit the region as passed as arguments to the Python function, but
let's not even do that, and rather discover the region from Python code.
It might look like this (untested):

from pymacs import lisp

def break_on_whitespace():
    start = lisp.point()
    end = lisp.mark()
    if start > end:
        start, end = end, start
    text = lisp.buffer_substring(start, end)
    words = text.split()
    replacement = '\n'.join(words)
    lisp.delete_region(start, end)

Note that if I was writing this for myself, for various stylistic reasons,
I might rather do:

from pymacs import lisp
from string import join

def break_on_whitespace():
    start, end = lisp.point(), lisp.mark()
    words = lisp.buffer_substring(start, end).split()
    lisp.delete_region(start, end)
    lisp.insert(join(words, '\n'))

relying on the fact that for the used LISP functions, `start' and `end'
may be given in any order.

> So what goes in my .emacs file?  First I import the module:
> (import-python 'manglers')

Exactly.  Yet, I might rename `import-python' into `python-load'.

> Then I can refer to (manglers-break_on_whitespace), right?

Almost.  An automatic underline to dash translation occurs while the module is
imported into Emacs, so use `manglers-break-on-whitespace'.

> And I think I can bind it to a key like so:
> (global-set-key (quote [f7]) (quote manglers-break_on_whitespace))

Essentially, yes.  The usual writing would be:

   (global-set-key [f7] 'manglers-break-on-whitespace)

as vectors quote themselves, and the apostrophe is easier on the eye! :-)
It should be even possible to bind the key from the Python side, maybe
using something like this, at the left margin, near the end of the module:

q = lisp.quote
lisp.global_set_key([lisp.f7], q(lisp.manglers_break_on_whitespace))

There is one thing that I know is currently missing, and that would prevent
to above to work today.  At `python-load' time, the function will not have
been marked "(interactive)", and I guess this is required for the function
to be usefully bound to a key.  I hope I'll find a nice way for this,
with the enlightening suggestions of this forum, of course! :-)

François Pinard

More information about the Python-list mailing list