1

I'm trying to use the display-buffer-alist variable to control how Emacs displays spawned inferior shells (ess-r in particular).

I'm using the display-buffer-alist value from ess doc:

(setq display-buffer-alist
      '(("*R"
         (display-buffer-reuse-window display-buffer-pop-up-frame)
         (reusable-frames . 0))))

However, when I start an R shell from some ess-r-mode buffer, the reusable-frames option does not seem to work: after creating a new frame displaying the R shell, Emacs displays a second instance of the ess-r-mode buffer in this new frame instead of returning to the old instance. Everything works correctly when I set reusable-frames globally:

(setq display-buffer-reuse-frames 0)

but this should not be necessary.

How can I make display-buffer-alist work properly without touching global settings?

Versions:

  • GNU Emacs 26.1
  • Linux 5.4.0-3-amd64 #1 SMP Debian 5.4.13-1 (2020-01-19) x86_64 GNU/Linux
  • Debian bullseye
2

How can I make display-buffer-alist work properly without touching global settings?

The fault here lies not with display-buffer, but with the ESS package, specifically the code in lisp/ess-inf.el. You should report this as a bug on their issue tracker, quoting the information below.


Firstly, "*R" is not a valid regexp, as the asterisk is a special character. In order to match it literally, it should be quoted with a literal backslash. So the correct regexp would be:

(rx "*R") ; => "\\*R"

or better yet, to avoid false positives:

(rx bos "*R*") ; => "\\`\\*R\\*"

So the correct overall incantation would be:

(setq display-buffer-alist
      `((,(rx bos "*R*")
         (display-buffer-reuse-window display-buffer-pop-up-frame)
         (reusable-frames . 0))))

or:

(setq display-buffer-alist
      '(("\\`\\*R\\*"
         (display-buffer-reuse-window display-buffer-pop-up-frame)
         (reusable-frames . 0))))

Secondly, the erroneous behaviour you describe happens only the first time one types C-cC-z (ess-switch-to-inferior-or-script-buffer) in an ess-r-mode buffer, i.e. before the corresponding inferior *R* process buffer has been created.

This is because ess-force-buffer-current calls ess-request-a-process with a non-nil noswitch argument when an inferior process does not already exist.

ess-request-a-process, in turn, does the following as its last step:

(if noswitch
    (pop-to-buffer (current-buffer)) ;; VS: this is weird, but is necessary
  (pop-to-buffer (buffer-name (process-buffer (get-process proc)))))

This call to (pop-to-buffer (current-buffer)) is wrong and is what causes your ess-r-mode buffer to appear a second time in the new frame. It was added in the following commit from 2012: https://github.com/emacs-ess/ESS/commit/b29ea8f934f7c08a512c73f14e914bca7229b3c1

I boldly say it is wrong because popping to the current buffer is quite an intrusive operation (as indicated by the bug in question), and the original intention of the author can almost definitely be written in a better way. I don't know what issue the author originally faced, but perhaps the ESS devs can figure it out.

| improve this answer | |
  • Please note that when the string starts with a "*" it is not interpreted as a regexp. So your initial statements are misleading. – Lionel Henry Aug 25 at 8:20
  • @LionelHenry Whether a string does or doesn't start with an asterisk does not change how it is interpreted. What determines that, is whether you feed said string to a function expecting a regexp. If you add "*a[bc]d" as a CONDITION in display-buffer-alist, it will match both buffer names *abd and *acd. So I think my initial statements are valid and your comment is mistaken. – Basil Aug 25 at 8:31
  • @LionelHenry If what you meant to say is that a leading asterisk is matched literally, then I think my initial statements remain useful, because that is still an invalid regexp and that behaviour should not be relied upon. – Basil Aug 25 at 8:33
  • You're right that it's because an initial asterisk is matched literally and the string is always interpreted as a regexp. It is not an invalid regexp though so your statements are still misleading. I do agree the behaviour should not be relied upon. – Lionel Henry Aug 25 at 11:17
  • @LionelHenry Only "ordinary characters" match themselves and nothing else; the asterisk is a "special character" - see (info "(elisp) Syntax of Regexps"). – Basil Aug 25 at 14:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.