emacs-devel
[Top][All Lists]
Advanced

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

Re: display-buffer-alist simplifications


From: Stefan Monnier
Subject: Re: display-buffer-alist simplifications
Date: Fri, 05 Aug 2011 15:22:36 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.50 (gnu/linux)

> The absurd consequence of this is that with `pop-up-frames' non-nil
> `ctl-x-4-map' becomes identical to `ctl-x-5-map' and
> `find-file-other-window' an alias for `find-file-other-frame'.  You
> won't find any explanation of this phenomena in the doc-strings of
> `pop-up-window' and `pop-up-frame' or in the documentation.

This just goes back to the problem of code let-binding pop-up-<foo>
instead of providing a SPECIFIER/RULE argument to display-buffer.

Fixing this is indeed (for me) the main goal of buffer-display-alist.

>> First we need to remove the switch-to-buffer' label (and other similar
>> labels, if any).
> Done.

Thanks.

>>> If the buffer is already displayed in some window, these options
>>> are ignored by that function.
>> That's often the right thing to do, so it's just a lack of flexibility
>> in the old code.
> It shouldn't be up to the code to decide whether a window shall be
> reused.

I already said that same-frame and same-window parameters in
special-display-regexps were mistakes, so there's no point complaining much
more about their quirks.

>>> (3) Users devising their own `special-display-function' have to ignore
>>> them or write their own code to handle them.
>> I don't know of any such user, so I don't worry about them too much.
> So apparently users are not interested in writing their own functions.

I tend to read it in another way: users are not interested in changing
this part of the behavior because it's good enough (and also the
FUNCTION of special-display-regexps provides the same flexibility, tho
in a typically more convenient way).

>> We already have 2 ways to name particular values (via either their value
>> or their function cell), so hopefully we can use one of the two as
>> "macro specifier" without having to introduce this new concept and its
>> attending code.
> `display-buffer-alist' already accepts both - primitive method
> specifiers and macro specifiers.

But it doesn't get it for free: it needs extra code to handle those,
plus extra documentation to explain what they do and how to use them.

>> Yes, that's true.
>> And the great thing about it is that it's all done by just one simple
>> hook: there is no special code designed to see whether the user
>> specified "reusing a window on another frame" or not.
> In fact.  Users have to write their own function in order to _avoid_
> that `display-buffer' does certain things.  It's precisely this behavior
> I wanted to put an end to.

If you oppose the FUNCTION hook, then we're in an irreconcilable disagreement.

I'm not sure why you choose to interpret it as a way to "avoid that
display-buffer does certain things" rather than, like any other Emacs
hooks, a way to override the default.

As a matter of fact, all my uses of FUNCTION (and I think Drew's as
well) are designed to make display-buffer do things that it otherwise
never does (e.g. redirect focus).

Of course, among all the things you can do with a hook, some of them are
to do less than the default.

>>> The complexity is built into the code of `special-display-popup-frame'.
>> I don't find it particularly complex.  It just tries each one of
>> the 5 different cases in turn: use FUNCTION,
> No.  If it calls FUNCTION it won't try any of the others.

If FUNCTION is not provided, it will try the others, so clearly it
tries the cases in turn.

I feel like you're tremendously defensive here, probably because you
feel like your work is being criticized.  I'm sorry you feel that way.
I really appreciate all the work you've put into it.

I like a lot of what I see.  But yes, I want to throw out a large part
of buffer-display-alist.  I know this is hard to take, but it's part of
the normal experiment/design/experiment/design cycle and it doesn't mean
your work was wasted, only that it was instrumental in coming up with
the final design, rather than the final code.  And still, most of the
code you wrote won't be affected, so we're only talking about
a small portion.

>> already-displayed,

> Usually this is a NOOP since `display-buffer' did check that case
> before.  So what usually happens is a needless extra call of
> `get-buffer-window'.

I'm not sure why you're so concerned about this reuse-window behavior of
special-display-popup-frame.  Ignoring the failed same-frame and
same-window parameters, you'll see that this reuse-window is almost
always the right thing to do: display-buffer would display the buffer in
a new dedicated frame, so if it's already displayed it's presumably in
a dedicated frame built previous with the same params and it would be
bad to create a second dedicated frame showing the same thing.

As for "calling get-buffer-window redundantly":
- I wouldn't worry about the redundancy performancewise.
- It's not always redundant.
- You're talking about the Emacs-23 implementation, whereas I'm
  concerned (and I'm talking here only) about the API.

> - With the default value of `display-buffer-reuse-frames',
>   `display-buffer' by itself does not reuse a window on another frame.
>   `special-display-popup-frame' would reuse such a window.  Hence,
>   `special-display-popup-frame' does not respect the user option
>   `display-buffer-reuse-frames' with the consequence that this function
>   is broken on systems where reusing frames doesn't work.

I have no interest in defending the Emacs-23 behavior here.  I only want
to streamline buffer-display-alist.
This said, I wonder which systems you're thinking of where "reusing
[dedicated] frames doesn't work".  I added [dedicated] since it's 99%
sure that the frame is dedicated in the scenario you're talking about.

> So `special-display-popup-frame' silently ignores a user option and
> overrides arguments in a much more aggressive and uncontrolled form than
> would be possible with `display-buffer-alist'.

Right, to some extent it sucks.  To some extent it provides
a good default.  Still: irrelevant to the design of buffer-display-alist.

Maybe the issue is that you want to be able to reproduce every detail of
the previous behavior in buffer-display-alist, whereas I don't.

>> same-window,
> Useless because overridden by `same-window-regexps' and
> `same-window-buffer-names'.

No: the whole point of `same-window' was to unify everything into
special-display-regexps and make the same-window-* horrors obsolete,
just like you're trying to unify everything under buffer-display-alist.

>> same-frame,
> Necessitated by the `pop-up-frames' overrides `pop-up-windows' paradigm
> explained above.

No: added because pop-up-frames applies to all buffers whereas we're
taking here about options which depend on the buffer name.

>> pop-up-frame.
> Which is the original and only reasonable motivation for
> `special-display-popup-frame'.

The already-displayed is intricately linked to the pop-up-frame because
the frame is dedicated.  That's why the already-displayed behavior has
been in special-display-popup-frame from the very beginning.

>>> You don't know what `special-display-buffer-names' does unless you read
>>> the code of that function.
>> I don't know what makes you think so.
> The two weeks I spent with Drew trying to understand it.

If there's complexity it's not really in special-display-buffer-names but
in how it sometimes behave similarly to (yet subtly differently from)
the rest of display-buffer.
And from where I stand the complexity is on the display-buffer side
rather than the special-display-buffer-names ;-)

In any case it's still not relevant to streamlining buffer-display-alist.

>>> The correct doc-string of `special-display-buffer-names' would have to
>>> explain in full what the code of `special-display-popup-frame' does.
>> What's missing?
> Are the arguments above not enough?

So, IIUC the missing parts are:
- the third arg of display-buffer is ignored.
- the second arg of display-buffer is ignored.
- it reuses windows regardless of (the ill-named) display-buffer-reuse-frames.
The first is a largely irrelevant bug since that arg is pretty much
never used (and your new code indeed gets rid of it).
The second is a real bug.  We don't usually document bugs.
The third is a pretty logically-evident behavior (tho only if you
ignore the same-frame and same-window failures), but sure, feel free to
document it.  Still a far cry from the complexity of buffer-display-alist.

>> It's also to force display-buffer (and switch-to-buffer when called
>> from Lisp packages) to use some other window/frame.  I don't want any
>> other buffer ever shown in my *Completions* window (which I carefully
>> size and place next to my minibuffer-only frame), same for my other
>> strongly-dedicated windows like *compilation*.
> Why did you have to dedicate the window for this purpose?  If
> `pop-up-frames' is non-nil, you get another frame before Emacs even
> tries to reuse a window not showing the buffer already.

A lot of code uses switch-to-buffer, kill-buffer, bury-buffer, ...

>>> I specially installed the quit-restore parameter for this
>>> purpose but it's currently mostly overridden by the dedicated status
>>> of the window.  Couldn't you try in your private code whether you
>>> could use that parameter instead and leave window dedication to what
>>> it should stand for according to its name: Avoid that `display-buffer'
>>> and/or `set-window-buffer' reuse a window for showing another buffer.
>> It might be an OK replacement for the soft dedication, yes.
> Then please try it by using `quit-restore-window' instead of
> `quit-window'.

I pretty much never use quit-window.

>>>> - `pop-up-window-split-unsplittable'.
>>> A silly leftover from the old code, IIUC.  I'd do away with it at any
>>> time.
>> You mean it's inherited from Emacs-23 or from your old code?  If it's
>> from your old code, then please remove it.  If it's from Emacs-23, maybe
>> as well, tho I'd first like to see where that feature was.

> A frame can have the parameter unsplittable

> `unsplittable'
>      If non-`nil', this frame's window is never split automatically.

I do know that part, yes.

> The specifier tells `display-buffer' to ignore that parameter.  If you
> say it's useless, I'll remove it.

The old code never ignored that parameter, right?  So I don't think we
should add a special feature to ignore that parameter, because I haven't
heard any request for such a feature.

>>>> IIUC the reason why you don't have just a single `where' parameter is so
>>>> that the merge between the specifiers given in display-buffer and
>>>> display-buffer-alist can be more fine-grained, right?  What were the
>>>> use-cases where you thought that was important?
>>> You understand correctly.  Once for compatibility with Emacs 23,
>> Where does compatibility require fine-grained merging?
> In `display-buffer-normalize-default'.

I don't mean "where in the code", but "in which concrete case".

OK, after thinking a tiny bit I see one case where "merging" might be
needed: the Emacs-23 `not-this-window' specifier (the only possible
specifier in Emacs-23) should preferably not be overruled by
display-buffer-alist.

OK, so that breaks my "RULE argument is only used if
buffer-display-alist doesn't specify it own RULE".

Hmm... so that means that the `not-this-window' arg is a constraint
imposed by the caller and that the user should not be able to override
(or close enough).  Not sure how to reconcile this with my design, indeed.

>>> once for applications,
>> Do you have concrete use-cases?
> I would have to go through the sources to find that.

That would be very helpful.

> `near-minibuffer' is even worse in this regard.  You can always try
> splitting the root window - it will get you a window just above the
> minibuffer, if there's room for it.  If you use bottom side windows you
> can specify the slot for the window which gives you quite good control.
> Anything else is unreliable - the window above the minibuffer might be
> the window that contains the most important information for the user at
> that moment - reusing it would be very strange, at least.

Oh yes.  And then there's the minibuffer-only frame case ;-)
But that's OK: it would have to be a best-effort in any case and the
user can override it.

>> I think writing a display-buffer-near-minibuffer function will be
>> simpler/cleaner than trying to come up with some clever way to
>> combine various specifiers.
> Any such function would run into just the same problems as
> `special-display-popup-frame'.

I do not regard those problems as significant.

>>> I can't deny that.  But that's how `display-buffer' alway worked, in a
>>> hard-coded form.
>> I don't find the two comparable because one is a piece of code which
>> provides one complex behavior via a simple API, whereas
>> display-buffer-alist provides a complex API.
> I suppose you really intended to write "whereas display-buffer-alist
> provides one simple behavior via a complex API" here ;-)

Hmm... let me think .. no ;-)

>>> Even if you use a rule based system, the rules must permit to specify
>>> that I want to pop up a window first and if that fails try reusing
>>> another one.
>> No.  You just have to provide one rule which reproduces the old complex
>> behavior (and could use that old code to do that).
> For this purpose I would have to leave in and document the old options
> forever.

That's OK.  They're written already.

>> If someone wants something else, she can write another rule with
>> another behavior, but we don't have to care about it nor about the
>> interaction between different rules as long as you restrict each rule
>> to be used in isolation.

> We'd get two, three, many instances of `special-display-popup-frame'.

Look more closely.  It'd be like:
- removing same-frame and same-window from special-display-popup-frame.
- removing the "ignore the 3rd arg of display-buffer" bug because we
  removed that 3rd arg.
- removing the "ignore the 2nd arg of display-buffer" bug because we
  redefined how it works.
- at this point special-display-popup-frame is limited to
  - reuse a window that shows the given buffer.
  - otherwise create a new frame with the provided params.
  I.e. as clean as it started, trivial to document and code.
- then, yes, provide multiple instances of such simple and clean things.


        Stefan



reply via email to

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