LINUX.ORG.RU

GNU Emacs: defadvice pop-to-buffer → pop-to-buffer-same-window

 , ,


0

1

Где-то между 24.4.1-й версией ГНУ Емакса и последним слепком из гита, сопровождающему shell.el стукнуло в голову, что M-x shell должна открывать оболочку не в текущем окне, как это было ранее, а в новом.

Материально это выражается в том, что в районе 720-й строчки оного shell.el (pop-to-buffer-same-window buffer) заменили на (pop-to-buffer buffer).

Мне такая перемена совершенно не по душе, как мне вернуть старое поведение?

Понятно, что я могу просто взять функцию shell, скопировать ее целиком в ~/.emacs и поправить, как я захочу.

Однако, насколько мне позволяют понять мои более чем скромные знания Елиспа и умение гуглить, правильно здесь будет написать что-то такое:

(defadvice shell-same-window (around shell activate)
  (letf (((symbol-function 'pop-to-buffer)
          (lambda (buffer &rest args)
            (pop-to-buffer-same-window buffer))))
    ad-do-it))

Однако это просто и молча не работает, а если попытаться откинуть в диагностических целях адвайс:

(letf (((symbol-function 'pop-to-buffer)
          (lambda (buffer &rest args)
            (pop-to-buffer-same-window buffer))))
  (shell))

то я получаю ошибку, смысл которой от меня ускользает:

pop-to-buffer-same-window: Variable binding depth exceeds max-specpdl-size

Где я накосячил?

★★★★★

Ну видимо pop-to-buffer-same-window внутри вызывает pop-to-buffer и получается рекурсия у тебя.

Bad_ptr ★★★★★
()

А вообще тут адвайс не нужен.
В современном емаксе это решается через display-buffer-alist. (pop-to-buffer вроде как внутри вызывает display-buffer)
Например:

(when (fboundp 'balance-windows-area)
  (defvar original-balance-windows (symbol-function 'balance-windows))
  (defalias 'balance-windows #'balance-windows-area))

(setq even-window-sizes nil)

(defun my/-display-buffer-at-bottom (buffer alist)
  (unless (or (window-minibuffer-p)
              (window-dedicated-p))
    (condition-case err
        (lexical-let ((window (split-window-below)))
          (when window
            (select-window window)
            (window--display-buffer buffer window 'window alist)
            (with-current-buffer buffer
              (setq window-area-factor 10)
              (add-hook 'kill-buffer-hook #'(lambda ()
                                              (with-current-buffer (current-buffer)
                                                (when (and (window-live-p window)
                                                           (window-deletable-p window))
                                                  (delete-window window)))
                                              ) t t))
            window))
      (error nil))))

(unless (version< emacs-version "24.1")
  (add-to-list 'display-buffer-alist
               '(".*" ;; тут ты можешь указать разные правила для разных имён буферов(regexp'ом) или major-mode(symbol'ом)
                 (display-buffer-reuse-window
                  ;;display-buffer-in-side-window
                  my/-display-buffer-at-bottom
                  display-buffer-use-some-window)
                 (reusable-frames . visible)
                 (side            . bottom)
                 (window-height   . 0.4))))

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

pop-to-buffer-same-window внутри вызывает pop-to-buffer

Ну, конечно, да. Что-то я протупил. А что тогда в таких случаях (вообще, не обязательно в данном) положено делать? Заадвайсить pop-to-buffer на pop-to-buffer с другими аргументами ведь точно так же нельзя.

Zmicier ★★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

В современном емаксе это решается через display-buffer-alist

Круто, спасибо.

".*"
тут ты можешь указать разные правила для разных имён буферов (regexp'ом) или major-mode (symbol'ом)

Про имена, кажется, все понятно, а вот с режимами — боюсь, не очень. В документации про них ничего нет. Можно пример?

Zmicier ★★★★★
() автор топика
Последнее исправление: Zmicier (всего исправлений: 2)
Ответ на: комментарий от Bad_ptr

А! Почитал повнимательней — там принимается регулярка или предикат, то есть для режима как-то так получается:

(add-to-list 'display-buffer-alist
             '((lambda (buffer action)
                 (with-current-buffer buffer
                   (eq major-mode 'shell-mode)))
               (display-buffer-reuse-window
                display-buffer-same-window)
               (reusable-frames . visible)))

Разве что я не вполне улавливаю, список не нужно завершать чем-нибудь для fallback’а?

Zmicier ★★★★★
() автор топика
Последнее исправление: Zmicier (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.