help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Critique my Code, learning elisp


From: Sam Peterson
Subject: Critique my Code, learning elisp
Date: 16 Oct 2006 01:39:16 -0700
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.4

I'm a long time user of GNU Emacs, but I've only recently dabbled in
Emacs Lisp.  I'm setting some useful functions for some friends of
mine in a C language class I'm taking to make composing C code
easier.  The trouble with learning Emacs Lisp for someone like me is
that I'm a perfectionist and it seems like there's multiple ways to do
just about everything in Emacs Lisp :).  Not only that, but it seems
like when I get an idea for a good elisp function, it turns out such a
thing already exists in Emacs, or somebody else has written a better
version of what I set out to do :(.  Or, something could have been
done much more easily with a Macro.

Take the following code:

(defun sams-c-wrap-if (beg end if-cond)
  "Function that wraps the region in a C language if statement"
  (interactive "r\nsCondition: ")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (insert (format "if (%s)\n{" if-cond))
      (c-indent-command)
      (newline)
      (c-indent-command)
      (goto-char (point-max))
      (insert (format "} // end if(%s)\n" if-cond))
      (c-indent-command)
      (setq end (point-max)))
    (c-indent-region beg end)))

This works splendidly.  However, I feel like an apprentice without a
mentor and I can't help but feel if what I've done here is sloppy or
poorly realized.  I also began to read up on skeletons.  I started to
realize I could accomplish the same thing via a skeleton like such:

(define-skeleton sams-c-wrap-if
 "Simple skeleton for wrapping c if statements"
 "Condition: " "if (" str ")" > "\n{" > "\n" > _ "}" >)

This works splendidly too.  So, "which is better"?  I realize this is
probably a subjective question, but I'm sure there's at least
contextual concerns to each.  For instance, I've written an "unif"
function to undo an if statement around the region:

(defun sams-c-unif (beg end)
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (goto-char (point-min))
      (if (not (looking-at " *if *(.*?) *$"))
          (error "Region doesn't contain a complete if statement")
        ;; else
        (kill-line 2)
        (setq beg (point))
        (goto-char (point-max))
        (previous-line 1)
        (beginning-of-line)
        (kill-line 1)
        (setq end (point))))
    (c-indent-region beg end)))

How does this compare?  It of course makes many assumptions about the
formatting of the if statement, but I haven't felt this is necessarily
evil as Emacs itself seems to do this about a lot of things, such as
its function movement commands.

The reason I've chosen this code is that it deals with wrapping a
region and there's so many ways to go about this.  In keyboard macros
you can go about it several ways:

* One way is to kill the region as the first command of the macro,
  then type what goes before the region, yank, and type what goes
  after the region.  This makes it so that it doesn't matter if point
  or mark is the furthest part of the region, but it does it at the
  expense of cluttering up the kill ring.

* A work around for this is to insert the region into a register,
  delete-region, type what goes before the region, insert register,
  then type what comes after the region.  This avoids cluttering the
  kill-ring at the expense of being a little more work to define.

* Yet one more way to go about is to simply type what comes after the
  region, exchange point and mark, type what comes before the region
  and exchange point and mark one last time.  This avoids having to
  store and delete text at the expense of requiring point be after
  mark in the region (otherwise the wrong thing ends up before and
  after the region).

There's probably even more ways to go about it but I'll stop there.

Not only can you do these things in elisp, but you can better it by
the fact that being passed the region interactively means that you
always know the beginning and end of the region at the start of your
function.  There's a small problem with just using buffer positions
however.  The insert function changes the buffer, so if you insert
what goes in the beginning of the region first, the end variable no
longer points to the end of the region.  I got around this in my code
above by narrowing to the region and using point-min and point-max.
This solves that problem, but is that overkill?  Is it normally better
to just insert what goes at the end of the region first, goto-char
beg, and insert the beginning of what goes in the region?  Heck, what
about goto-char end, push-mark, goto-char beg, insert, exchange point
and mark, insert end?  Are there performance trade-offs?  What is
"the" way to do this.  Am I stressing out waaaay too much about this?
Should I just do something that works and be secure in the knowledge
that performance concerns are probably not a big deal for something
like this?  Is something like this already built into cc-mode or Emacs
and am I wasting my time trying?  Was I abused as a child with Basic?
Will I ever get my degree?  What is the meaing of life?

-- 
Sam Peterson
skpeterson At no spam ucdavis.edu
The curious little elisp learner.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]