Дзен отображения буферов
В самом простом случае кадр всегда содержит одно-единственное окно, которое можно использовать для отображения буфера. Поэтому буфер в этом окне успешно разместит последний вызов display-buffer.
Поскольку работать с таким кадром не очень удобно, Emacs по умолчанию позволяет создавать более сложные компоновки кадров, управляемые значениями по умолчанию размера кадра и параметров split-height-threshold и split-width-threshold. При отображении буфера, который ещё не показан в кадре, единственное окно этого кадра либо разделяется, либо повторно используется одно из двух его окон.
Поведение по умолчанию перестаёт действовать, как только пользователь настраивает один из этих пороговых параметров или вручную меняет компоновку кадра. Поведение по умолчанию также перестаёт действовать при вызове display-buffer с аргументом action, не равным nil, или если пользователь настраивает один из параметров, упомянутых в предыдущих подразделах. Скоро освоение display-buffer может стать утомительным занятием из-за множества применимых действий отображения и возникающих в результате компоновок кадров.
Однако отказываться от функций отображения буферов и возвращаться к подходу «разделить & удалить окна» тоже не стоит. Функции отображения буферов предоставляют программам на Lisp и пользователям основу для согласования их различных потребностей; сопоставимой основы для разделения и удаления окон не существует. Кроме того, функции отображения буферов позволяют хотя бы частично восстановить компоновку кадра при последующем удалении из него буфера (см. Закрытие окон).
Ниже приведён ряд рекомендаций, которые помогут преодолеть описанное выше разочарование и не допустить, чтобы буферы буквально терялись между окнами кадра.
- Составляйте действия отображения без лишних усилий
-
Составление действий отображения может быть непростой задачей, поскольку приходится объединять функции действий и списки свойств действий в один большой список. (По историческим причинам мы не смогли заставить
display-bufferподдерживать для них отдельные аргументы.) Может помочь запоминание нескольких базовых форм, например приведённых ниже:'(nil (inhibit-same-window . t))
задаёт только элемент списка свойств действий и не задаёт функцию действия. Единственная цель этой формы — не дать функции
display-buffer-same-window, заданной в другом месте, показать буфер в том же окне; см. также последний пример предыдущего подраздела.'(display-buffer-below-selected)
напротив, задаёт одну функцию действия и пустой список свойств действий. Чтобы объединить эффекты двух приведённых выше спецификаций, можно написать форму
'(display-buffer-below-selected (inhibit-same-window . t))
чтобы добавить ещё одну функцию действия, можно написать
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t))
а чтобы добавить ещё один элемент списка свойств, можно написать
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer))
Эту последнюю форму можно использовать в качестве аргумента action для
display-bufferследующим образом:(display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer)))
В настройке
display-buffer-alistеё следует использовать так:(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer))))Чтобы добавить настройку для второго буфера, следует написать:
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer)) ("\\*bar\\*" (display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . visible)))) - Уважайте друг друга
-
display-buffer-alistиdisplay-buffer-base-action— пользовательские параметры, и программы на Lisp ни в коем случае не должны задавать или переопределять их.display-buffer-overriding-action, напротив, предназначен для приложений, которые редко используют этот параметр, а если используют, то с особой осторожностью.В более ранних реализациях
display-bufferчасто возникали конфликты между пользователями и приложениями из-за значений пользовательских параметров, таких какpop-up-framesиpop-up-windows(см. Дополнительные параметры отображения буферов). Это было одной из основных причин переработкиdisplay-buffer— требовалось создать ясную основу, определяющую, что разрешено делать пользователям и приложениям.Программы на Lisp должны учитывать, что из-за пользовательских настроек буферы могут отображаться неожиданным образом. Их дальнейшее поведение ни в коем случае не должно исходить из предположения, что буфер показан именно так, как было указано в аргументе action вызова
display-buffer.Пользователям не следует вводить слишком много чрезмерно строгих ограничений на отображение произвольных буферов. Иначе они рискуют утратить возможность показывать буфер определённым образом для конкретной цели. Предположим, программа на Lisp предназначена для сравнения разных версий буфера в двух окнах, расположенных рядом. Если настройка
display-buffer-alistпредписывает всегда показывать такие буферы в выбранном окне или под ним, программе будет трудно настроить нужную конфигурацию окон с помощьюdisplay-buffer.Чтобы задать предпочтительный способ отображения произвольного буфера, пользователям следует настроить
display-buffer-base-action. В предыдущем подразделе приведён пример для пользователей, предпочитающих работать с несколькими кадрами. Параметрdisplay-buffer-alistследует оставить для отображения определённых буферов определённым способом. - Рассмотрите возможность повторного использования окна, в котором уже показан буфер
-
В целом и пользователям, и программистам на Lisp стоит учитывать ситуацию, когда нужный буфер уже показан в окне, и повторно использовать это окно. В предыдущем подразделе мы показали, что если этого не делать должным образом,
display-bufferможет постоянно открывать новый кадр, хотя кадр с этим буфером уже существует. Лишь в некоторых случаях повторно использовать окно нежелательно, например когда в нём нужно показать другую часть буфера.Поэтому
display-buffer-reuse-window— одна из функций действий, которую следует использовать как можно чаще, как в аргументах action, так и в настройках. Элементinhibit-same-windowв аргументе action обычно позволяет учесть наиболее распространённый случай, когда повторного использования окна с буфером следует избегать: когда это окно выбрано. - Переключайте фокус на выбранное окно
-
Для тех, кто работает с несколькими кадрами, это очевидно: кадр с буфером автоматически поднимается и получает фокус, если только элемент
inhibit-switch-frameне запрещает этого. Для пользователей, работающих с одним кадром, эта задача может быть значительно сложнее. В частности, в этом отношенииdisplay-buffer-pop-up-windowиdisplay-buffer-use-some-windowмогут мешать работе. Они разделяют окно или используют, казалось бы, произвольное окно (часто самое большое или давно не использовавшееся), отвлекая внимание пользователя.Поэтому некоторые программы на Lisp пытаются выбрать окно в нижней части кадра, например, чтобы показать буфер рядом с окном минибуфера, где пользователь должен ответить на вопрос, связанный с новым окном. Для действий, не связанных с вводом, может быть предпочтительнее
display-buffer-below-selected, поскольку выбранное окно обычно уже привлекает внимание пользователя. - Следите за тем, какое окно выбрано
-
Многие приложения вызывают
display-bufferвнутри временных переключений окон, создаваемых вызовамиwith-selected-windowилиselect-windowс аргументом norecord, не равнымnil. Почти всегда это плохая идея, поскольку окно, выбранное внутри такого временного переключения, обычно не является окном, выбранным в конфигурации, представленной пользователю.Например, если пользователь добавил элемент списка свойств
inhibit-same-window, этот элемент позволил бы избежать окна, выбранного в пределах временного переключения, а не окна, выбранного в результирующей конфигурации. Даже если такой элемент не добавлен, поведение может оказаться странным. Если в кадре есть одно отображаемое окно, вычисление следующей формы(progn (split-window) (display-buffer "*Messages*"))
покажет внизу окно с буфером *Messages*, оставив выбранным другое окно. Вычисление следующей формы
(with-selected-window (split-window) (display-buffer "*Messages*"))
покажет *Messages* в окне сверху и выберет его, чего обычно не должна делать
display-buffer.С другой стороны, вычисление следующей формы
(progn (split-window) (pop-to-buffer "*Messages*"))
правильно выберет буфер *Messages*, а следующая форма
(progn (split-window) (with-selected-window (selected-window) (pop-to-buffer "*Messages*")))этого не сделает.
Кроме того, вызовы таких функций действий, как
display-buffer-use-some-windowиdisplay-buffer-use-least-recent-window, которые предполагают, что время использования выбранного окна больше, чем у всех остальных окон, могут не создать окно в соответствии со своими спецификациями.Поэтому приложению, которому необходимо временное переключение окон, следует попытаться отложить вызов
display-bufferдо завершения этого переключения.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/The-Zen-of-Buffer-Display.html