[Top][All Lists]

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

Re: end-of-defun is fubsr.

From: Alan Mackenzie
Subject: Re: end-of-defun is fubsr.
Date: Tue, 3 Feb 2009 18:58:12 +0000
User-agent: Mutt/1.5.9i

Hi, Stefan!

On Tue, Feb 03, 2009 at 12:13:19PM -0500, Stefan Monnier wrote:
> > end-of-defun (in .../lisp/emacs-lisp/lisp.el) is buggy, at least when an
> > end-of-defun-function has been defined:

> > (i) After calling end-of-defun-function, e-o-d takes it upon itself
> > to advance an arbitrary amount of whitespace/comments.  This is what
> > you (Miles) were complaining about.

> It should only move from "right after the closing }" to BOL 7.
> Not "an arbitrary amount of whitespace".  Of course, there might be

Sorry, yes, I was wrong.  It moves at most one line forward.

> a bug, but my guess is that your end-of-defun-function jumpts to BOL
> 7 rather than right after the brace.  So the problem is a disagreement
> between the two.

Exactly.  There is no documentation which says whether a [BE]OD-function
should adjust for WS/Comments or not.  I think it should, because the
variable name doesn't end in "-raw-function", and the major mode knows
better than the Emacs core where the best finishing point is.

How about:
(defvar beginning-of-defun-function ....
  "If non-nil, function for `beginning-of-defun-raw' to call.
  This is used to move to the beginning of the defun instead of using the
  normal recipe (see `beginning-of-defun').  Major modes can define this
  if defining `defun-prompt-regexp' is not sufficient to handle the
  mode's needs.

  The function takes one optional arg, the number of defuns to go back.
  It should leave point at a sensible place just before the defun starts,
  e.g. at the start of the line, or before a block comment preceding it.
  It should return non-nil on success, or nil on failure.

> > (ii) When point is BETWEEN two C functions (more precisely JUST AFTER
> > the end of the previous function), C-M-e doesn't move over the next
> > function.  This is because it gets its knickers in a twist, first
> > calling BOD-raw, then EOD-function, trying to check if its succeeded
> > yet, etc. .........   This is crazy!

> This might be linked to the above problem.  For Elisp it seems to
> work correctly.

The problem is that end-of-defun calls beginning-of-defun-raw at each
iteration (over ARG).  It thus discards the information as to whether
point began in a defun or between 2 defuns.

> > This mechanism is entirely unsuited to CC Mode.
> > c-\(beginning\|end\)-of-defun have a very high setup (determining
> > whether point is within a function's block, or header, etc.) and tear
> > down (locating the start of a function's header) time, but is lightening
> > fast zipping through brace blocks in between.  This high setup/teardown
> > time has been the cause of several "it's too slow" bugs (e.g. for C-x 4
> > a) in the last few years.

> > The current implementation of end-of-defun is essentially calling
> > c-end-of-defun AND c-beginning-of-defun in a loop, sometimes calling
> > them twice in each iteration.  This is slow for large ARG.  It's crazy!
> > To see this, go into buffer.c, and do

> >     C-u 106 C-M-e

> > .  On my box, this takes 20s.  By contrast, C-u 106 C-M-a takes about
> > 0.5s.

> I don't consider "C-u 106 C-M-e" as a common operation.

No, but when a simple operation takes 20s on a faster machine than a
12 MHz 386SX, something's less than optimal.  And when there are enough
top-level declarations without braces, this time will extend to several
minutes.  There are enough CC Mode users that quite a few will be calling
C-M-e with repeat counts.

What's bugging the Hades out of me is that I've put a LOT of effort into
optimising c-\(beginning\|end\)-of-defun, and that's being rendered
completely useless, at least for C-M-e, by an inept way of calling these
functions.  Several bug reports which made this work necessary came
directly from Emacs Developers (for example, C-x 4 a taking a minute to
run, or hassle with potential K&R regions taking just as long).

I foresee that immediately after the release of Emacs 23 there will be at
least one complaint about the sluggishness of C-M-e, and my reply will be
to agree, to apologise for it, and to tell the complainer just to bind
C-M-[ae] in c-mode-base-map.  Chance are, there will be several.  Hello,
lots of unrewarding repetitive and uncreative drudge work.

Having come this far, why can't we just do the job right?  Or, failing
that, at least bind C-M-[ae] in c-mode-base-map in Emacs-23?

Surely there's nobody here who isn't sick and fed up with this defun
movement business?  Surely to goodness, after 25 years, we should be able
to do major-mode specific defun movement as a matter of course?

> > Also, the semantics of end-of-defun-function have been completely
> > changed (specifically, in lisp.el v1.82, 2007-11-26) so that it now
> > has only a coincidental connection with what its name suggests.

> Huh?  It hasn't completely changed.  Some details have changed to make
> it easier to implement a simple end-of-defun-function, while making
> sure that end-of-defun behaves consistently.

It's changed from "move to next end of function" to "move to the end of
the function at whose beginning we now are", and its default value is
`forward-sexp'.  `c-end-of-defun' was a good fit for the variable as it
formerly was, but is now severely suboptimal.

> It was mostly a matter of fixing end-of-defun which was completely
> broken when passed negative arguments.

Surely we have two cases: if the major mode supplies a EOD-function (old
semantics), e-o-d should simply invoke it.  Otherwise (e.g. Elisp), why
not just do (scan-lists -1 1) (on the last iteration) to locate the
pertinent ")"?

> > 1/- end-of-defun-function should be restored to its prior semantics, and
> > additionally be passed the ARG argument in the same way as BOD-function.

> Not sure about restoring the previous semantics.  But I could agree to
> the additional ARG argument, which could even let it "take over" (so
> beginning-of-defun-raw is not called in that case).

:-)  Let's do it!

> > 3/- end-of-defun should be restructured along the lines of
> > beginning-of-defun.

> I don't think that's a good idea.  The main reason is to deal with
> languages that allow nested functions.

Don't follow - In the upcoming CC Mode 5.32 code (in the CVS repository
at SourceForge), C-M-[ae] works just fine for C++ defuns nested inside
classes/namespaces and so on.  The mechanism is entirely within CC Mode.

>         Stefan

Alan Mackenzie (Nuremberg, Germany).

reply via email to

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