Emacs as a Perl IDE
|
This is a text form of a talk/demo given at the San Francisco
Perl Mongers on February 28th, 2006. I was talking about using
Emacs as a perl IDE, with some emphasis on what can be done with
the perlnow.el package
that I wrote.
|
Table of contents:
Gnu Emacs is a very old software project:
o pre-dates unix
o version 21 and counting
(and the FSF ain't all that fast about
doing major releases).
o there are a lot of "firsts" that
can be cited for the emacs world:
Emacs: the first IDE.
Emacs: the first windowing system
(though not graphical).
Emacs: the first free software
(aka open source) project
... and so on.
(Emacs invented television.)
A claim of emacs fans: emacs supports
the widest range of languages of any IDE.
Here "support" largely means
syntax-coloring and indentation
rules.
The basic thing that *I* expect from
an IDE is definitely supported by emacs:
the integration of error listings and
navigation features, so you can jump
directly to the source of the next problem.
Emacs culture, and the great war with "vi",
makes an interesting study even if you're
not into learning to use emacs.
There's a pattern in technical
religious wars: you try to tell
someone about some cool feature,
and they respond "oh, you don't
*need* that crap", but then a
few years later after the
feature has been cloned, they First they laugh at you,
all start going "look, we have then they imitate you,
that crap now too!" then they laugh at you again
(and then you don't win).
Emacs: tomorrow's crap, today.
Since there are a lot of ideas that were
invented for emacs and then ignored and
reinvented later, it may seem like nothing
is called by it's right name:
FAMILIAR: EMACS JARGON:
windows frames
subwindows windows
("panes" in MS;
"frames" on the
web, as David
pointed out)
cut kill
paste yank
copy copy-as-kill
clipboard kill-ring
??? yank-pop
Is there any analog of yank-pop?
(In KDE, says Josh)
The "kill-ring" is
essentially a stack.
When you "kill" a block of text, it gets
pushed on to the top of the stack, and
doing a "yank" pops it off, and if you
like you can continue doing "yank-pop"
commands, cycling through the kill-ring.
This kind of notion evidently
offends Steve Jobs' sense of
minimalism, hence we're all stuck
with "clipboards" that apparently
have very *tiny* clips that can only
hold one page at a time. And if you
try and shove a second page on top
the first page evaporates.
But that, of course, is an
easy-to-use logical metaphor... (A complaint
I've borrowed
Unlike this absurdly from Ted Nelson.)
incomprehensible emacs
stuff.
And in addition to the kill-ring
there are also "registers":
Myself, I use a custom keystroke
macro in dired that stashes the
directory and filename in registers
"p" and "n", so they can be used
again easily, in for example an
emacs sub-shell window.
So: there are more nooks to stash
things inside of emacs than
just a single-page clipboard.
And that alone means there's some
advantage to doing everything ("Small things can
inside of the emacs if you can. can make big
differences" has
Small things that add up: been one of my
slogans, lately.)
If you get away from the "do one
thing and do it well" doctrine,
you find benefits like this: it
helps for the pieces to be able
to talk to each other easily. Divide and conquer,
integrate and rule!
(or something)
dired: the first file manager
I've always pronounced
The layout is intuitively obvious... if this "DIRE-ed", but a
you've been doing "ls -la" all your life. friend of mine says
"DEAR-ed". I don't know
Some features: which is standard.
o Rename an open file?
Emacs tracks the name change:
(if you save again later it
goes to the right place).
o "!" runs a shell command on the
current file, suggesting a guess
based on the extension,
e.g. "*.tar.gz" gets:
gunzip -qc * | tar xvf -
o Wide variety of built-in commands,
way beyond the typical file manager:
e.g. you can create symlinks (S) or
relative symlinks (Y).
And this is all text: you can copy
it, mail it to someone, etc.
But it's not *dead* text: it's an
active list that you can run (Another of my
commands on with a few keystrokes. slogans:
"More active lists!".)
Version control integration:
The included vc.el package does basic
CVS and RCS quite well.
Central feature is one command that
does the next logical action on the file
("C-x v v"): (Note they original
author on this
register the file package is Eric
check in S. Raymond, but many
check out... other's have worked
on it since then, so
vc.el has other commands to view the log if you're an ESR
of change messages, do diffs against hater you have an
previous versions, and so on. out.)
One thing that really
impressed me about
vc.el is how (In contrast, command-line
absolutely painless it RCS has a stale interface
makes keeping files that does the wrong thing
under RCS control. by default. Need to learn
the meaning of obscure
If at any moment you flags: -u, -l...)
decide you want to put
a file you're editing
under version control,
you just hit "C-x v v".
If there's no RCS (And if there is
subdirectory yet, it a CVS, it knows it
There are *no* creates one. should use cvs
setup hassles. instead.)
For the newer version control
systems I think it's an open
question whether we'll use
dedicated *.el packages for each
system (e.g. I used to use p4.el
with perforce) or if they'll
succeed in extending vc.el to
cover them all.
Apparently vc.el works with subversion and gnu arch now:
gnu.org:version systems
At last, perl:
The default perl mode for GNU emacs
is still perl-mode, but it also ships
with a new one that has better
(though still not perfect)
comprehension of the syntax:
cperl-mode
(written by
Ilya Zakharevich,
an old perl-porter).
Has a number of *very* odd features
(e.g. a "hairy mode" that tries to fill in
closing braces and such at the moment you
type an open brace).
Simple feature that I like: you can run "perldoc -f"
on the keyword under the cursor. If you
bind this to a key you can review the docs
for any given function instantly, the moment
you wonder about it...
("what does 'stat' return again?).
emacswiki: cperl-mode
perlnow - elisp glue for perl tasks
A very slight package really,
but "small things => big differences"
Uses a new project called "template.el",
not the emacs-standard "tempo.el".
(I think tempo is the wrong way around:
it's not tokens embedded in text, but
rather strings embedded in code; and the (Note: I've gotten a
code is elisp: overall this is unlikely nibble from someone with
to appeal to perl people.) commit privileges about
including perlnow in GNU
emacs, though I suspect I
may need to add support
for tempo.el first. But
I'm not dropping support
for template.el.)
Anyway, perlnow helps out with
three major classes of common perl
programming tasks:
(1) initial code creation
(2) syntax checking / running code / running the debugger
(3) creating/running tests
perlnow: initial code creation
Say you have an idea for:
a script.
a module.
an OOP module.
a CPAN package.
a test script
a script using a module.
o while looking at the
module source
o while looking at a module
man page.
Using perlnow, you typically will hit just a
few keystrokes, answer a question or two
about names and locations, and then you'll
get kicked into a new file buffer using the
appropriate template for what you want to do.
Note: a "small thing" about perlnow: you have
separate commands to create a procedural
module or an object-oriented module, and these
use separate templates even though both types
of files have the same file extension
("*.pm").
Emacs often uses the file extension to
guess what it should do: sometimes it
helps to provide additional hints.
perlnow: syntax checking / running code / running the debugger
A key feature with perlnow is that you
have different run strings associated
with each file buffer.
perlnow tries to guess a good runstring,
but also let's you modify the string on
the fly -- e.g. you can add command line
args and redirects.
When you do a "check" or a "run" command,
you'll see error messages and output appear
in another emacs window, and you can You can also mouse
hit the "next-error" command (usually around and click on
control x back-apostrophe) to immediately an error message,
jump to the file and line number where (if you're the sort
the error occurred. that fondles rodents).
Note: this utilizes the standard emacs
"compile" facility, perlnow just tries to
feed a more appropriate run string than Last I looked,
emacs "compile" would use. compile guessed
"make -k" for
It's worth noting that the emacs perl code: But they'll
compile/next-error cycle can be completely definitely
very useful given *any* command useless. fix this
that spits out file names and at some
line numbers in an appropriate way. point...
For example, I'm a fan of the
emacs "grep" and "grep-find"
commands (which do what you'd
expect).
perlnow: running the perl debugger
When you use perlnow to jump into the emacs
front-end to the perl debugger, you
run it using the runstring that's
associated with this buffer.
If you did this with a raw "M-x perldb",
the default is just to run perldb the last Note to elisp programmers:
way you ran it, even if that makes no "buffer local variables"
sense for the current buffer. are your friend. Don't
hesitate to use them,
despite the (mild)
By the way: the perldb is discouragement in the
pretty cool, and it's even cooler elisp docs.
with a front-end like emacs,
which shows the code in one
window and the control panel
in another.
The code buffer is always live:
when you find a problem, you can
fix it instantly (though you
need to restart the debugger
with an "R" to get it to read
the change).
Some perldb commands: Use "s" or "n"
to step through the code
("s" goes down into sub calls,
"n" treats them as one step),
and "x" to do dumps of variables.
"b" sets a breakpoint somewhere
in the code, and "c" let's you
chug away to that point.
A half-hour (hell, maybe ten minutes)
of playing around with the debugger
and you'll know all (well, most) you
need to know about it.
Do it sometime when you're *not*
actually worrying about a bug, though.
perlnow: creating/running tests
One of the nice touches about perlnow:
you can jump straight from some code to
editing a *.t file to test the code.
It tries to find an existing test file
and edit that, but if not it will create
a new one in an intelligent place, using
the standard template.
There's a range of different places
it hunts for an appropriate test file,
using a few different possible naming
conventions. (Both need to be expanded,
though...)
You can specify a policy that determines
where it will try to create *.t files,
and what they'll be called.
Some common practices are not yet supported:
o Multiple test files with a numbered prefix.
o Separate parallel tree of test files
The existing system works well
(despite that bug in the demo...)
*if* you're willing to confine That bug popped up
yourself to a convention such as because I was using a
putting each test in a nearby "t" large font, and hence a
directory, and using a related small number of lines.
basename, (e.g. "Modular-Stuff.t" I don't usually run
for "Modular::Stuff"). like that, so I'd never
hit it before.
(Also: I have a funny mental
block on "prove". One of these
days, I'll get to it... maybe
it should be integrated into
perlnow...)
There are a bunch of little niceties built into
perlnow (of varying degrees of silliness)...
For example, if you're looking at a module
and you hit the "new script" command, you'll
get a "use" line inserted that points at
the module you were looking at.
This also works (mostly) if you're looking
at the man page for a module.
A little touch that I personally like a lot:
if the module you were looking at is not in
your @INC, the new script will have an
appropriate FindBin/use lib incantation so
that the script can find the module.
Copying a runstring to another buffer:
This is a little trick that I use a lot...
o Issue the perlnow command to edit the runstring.
o Kill the line ("cut"), then interrupt the edit.
o Switch to a different code buffer.
o Edit the runstring there and paste in the runstring from
the kill-ring.
This way you can clone the runstring that
perlnow guessed for one file and move it to
another manually: sometimes *you* know that
you want to test the module in front of you
by running a particular script, but there's no
way perlnow could know that unless you tell it.
Customizing emacs with perl.
o EPL/sepia
There's a newish, fancy approach to
customizing emacs in perl called "EPL". This
let's your emacs and perl talk to each other
through interprocess communication: Emacs::Lisp
There's an attempt at doing some perl IDE-like stuff
called sepia
In my last few attempts at playing with these,
I've run into too many installation hassles
and given up.
That was one of the
motivations for doing
perlnow.el as "pure" elisp.
It's also one of the
reasons I've been dreaming (We'll see if
of "Oyster"... see I still feel
Crazy Dreams below. the need after
switching to
a more modern
linux distro.)
o shelling out
There's still some mileage in the
old-fashioned method of just calling perl
in a new process and grabbing the returned
information.
An example follows...
Given a perl script like so:
#!/usr/bin/perl -w
# scramble_case - doom@kzsu.stanford.edu
use Text::Capitalize 0.3 qw(scramble_case);
while(<>){
print scramble_case($_);
}
And with this entry in my ~/.emacs:
(defun doom-run-scramble_case-region (start end)
(interactive "r")
(let ( (command "scramble_case") )
(shell-command-on-region start end command nil t "*error*")
))
(global-set-key "\M-o\M-s" 'doom-run-scramble_case-region)
Then, with an "Alt-o Alt-s":
I can take a sample of text like this sentence,
and transform it into something like...
i CaN tAKe a SampLe of teXT LIKe This SEnTenCE,
And tRAnSfOrm IT inTo SOMEThINg lIKE...
Someone on the SF perl mongers list was asking about
"support for perltidy", but it's actually not that
difficult to support any sort of text manipulation
script from within emacs. Here's another .emacs example:
;; From: http://www.perlmonks.org/index.pl?node_id=380724
;;
;; Put this in your ~/.emacs file, select the region you
;; want to clean up and type C-xt or M-x perltidy-region.
(global-set-key "\C-xt" 'perltidy-region)
(defun perltidy-region ()
"Run the perltidy parser on the current region."
(interactive)
(let ((start (mark))
(end (point))
(shell-command-default-error-buffer "perltidy-errors")
(command "perltidy"))
(shell-command-on-region
start
end
command
t t
shell-command-default-error-buffer)))
Babel-66: the many languages conundrum
The language wars are a familiar feature of the landscape.
The subject of IDEs lands us in the heart of this battleground.
o Everyone wants to use their
favorite IDE for every language
that they work in.
o Everyone wants their IDE to be
customizable in their favorite
language.
But we all use different languages.
The IDE must appeal to many cultures,
but also must have a culture of it's own.
Possible resolutions:
Write a bunch of IDEs one for
each favorite language, (which
also supports every other
language).
Write an IDE in one primary
language, but allow multiple
different secondary
customization languages.
Variant: Write library routines
in one or more languages, build
an IDE by gluing them together
using a "primary" language.
Customization: one primary,
multiple secondaries, which may
or may not be in the glue language.
emacswiki:the multiple extension language problem
I submit that there is no
rigorously correct solution...
all we can do is try to be
reasonable.
Crazy dreams
o Oyster: a perl-centric linux distro
There are too many setup annoyances that
get in the way of creating the ultimate
perl-hacking box. Maybe it could be done (I dislike messing
just once, instead of over-and-over? with linux system
administration, but I
might dislike it less
(Imagine having an entire CPAN snapshot if I could at least
installed by default... Well okay, maybe pass on the results
just a CPAN subset would be advisable. of my work to other
Still, a modern installation needs much more people.)
than the standard library.)
o Re-write emacs in perl
Perl people, as is their wont, have
been re-implementing editor functionality
in perl code (e.g. Conway's Text::Autoformat).
Rather than extending emacs, maybe it's
time to re-write it in another language? (Argh, yet
*another*
emacs fork?)
Perl::Editor
o Port elisp to Parrot
Elisp is *not* that complicated a language,
porting it to Parrot should be easy:
then you could have an emacs clone running
on a different, newer runtime engine.
(Possible complication: some parts of emacs
were re-written in C code for speed.)
Maybe a Parrot emacs would be
(1) faster
(2) poly-threaded
(3) customizable in other Parrot languages.
(Or maybe not)
The good Randal: The evil twin:
"Given that I use the kitchen "If you can't program careful
sink of programming languages enough to not need a debugger,
(Perl), it only makes sense then either slow down your rate
that I use the kitchen sink of of coding, or pick a different
editors (Emacs)." profession. Please."
-- Randal L. Schwartz -- Randal L. Schwartz
[1] [2]
[1] As quoted on perlmonks by "santonegro"
[2] On perlmonks, December 28, 2000
Further Reading
|
|
- Steve Yegge does an excellent emacs lisp introduction and
makes fun of Eclipse in the process:
- My Save Excursion
- (Even his excessively long introduction about how he writes
excessively long pieces is pretty funny.)
|
Joseph Brenner,
01 Mar 2006