29.9 Перекомбинация окон

При удалении последнего родственного окна W его родительское окно также удаляется, а W заменяет его в дереве окон. Это означает, что W должно быть перекомбинировано с родственными окнами своего родителя для образования новой комбинации окон (см. Окна и кадры). В некоторых случаях удаление живого окна может даже повлечь за собой удаление двух внутренних окон.

     ______________________________________
    | ______  ____________________________ |
    ||      || __________________________ ||
    ||      ||| ___________  ___________ |||
    ||      ||||           ||           ||||
    ||      ||||____W6_____||_____W7____||||
    ||      |||____________W4____________|||
    ||      || __________________________ ||
    ||      |||                          |||
    ||      |||                          |||
    ||      |||____________W5____________|||
    ||__W2__||_____________W3_____________ |
    |__________________W1__________________|

Удаление W5 в этой конфигурации обычно приводит к удалению W3 и W4. Оставшиеся живые окна W2, W6 и W7 перекомбинируются, образуя новую горизонтальную комбинацию с родителем W1.

Однако иногда имеет смысл не удалять родительское окно, подобное W4. В частности, родительское окно не должно удаляться, когда оно использовалось для сохранения комбинации, вложенной в комбинацию того же типа. Такие вложения имеют смысл для того, чтобы гарантировать, что при разбиении окна и последующем удалении нового окна Emacs восстановит компоновку соответствующего кадра в том виде, в котором она существовала до разбиения.

Рассмотрим сценарий, начинающийся с двух живых окон W2 и W3 и их родителя W1.

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W3_________________||
    |__________________W1__________________|

Разбейте W2, чтобы создать новое окно W4, как показано ниже.

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W4_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W3_________________||
    |__________________W1__________________|

Теперь при вертикальном увеличении окна Emacs пытается получить соответствующее пространство от его нижнего родственного окна, если такое окно существует. В нашем сценарии увеличение W4 отнимет пространство у W3.

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W4_________________||
    | ____________________________________ |
    ||_________________W3_________________||
    |__________________W1__________________|

Удаление W4 теперь отдаст всё его пространство W2, включая пространство, ранее отнятое у W3.

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||_________________W3_________________||
    |__________________W1__________________|

Это может быть неочевидным, особенно если W4 использовалось для отображения буфера только временно (см. Временные отображения), и вы хотите продолжить работу с исходной компоновкой.

Это поведение можно исправить, создав новое родительское окно при разбиении W2. Описываемая ниже переменная позволяет это сделать.

Пользовательская опция: window-combination-limit

Эта переменная управляет тем, должно ли разбиение окна создавать новое родительское окно. Распознаются следующие значения:

nil

Это означает, что новому живому окну разрешается совместно использовать существующее родительское окно, если оно существует, при условии, что разбиение происходит в том же направлении, что и существующая комбинация окон (в противном случае всё равно создается новое внутреннее окно).

window-size

Это означает, что display-buffer создает новое родительское окно, когда разбивает окно и ему передается запись window-height или window-width в аргументе alist (см. Функции действий для отображения буфера). В противном случае разбиение окон ведет себя как для значения nil.

temp-buffer-resize

В этом случае with-temp-buffer-window создает новое родительское окно при разбиении окна, если включен temp-buffer-resize-mode (см. Временные отображения). В противном случае разбиение окон ведет себя как для nil.

temp-buffer

В этом случае with-temp-buffer-window всегда создает новое родительское окно при разбиении существующего окна (см. Временные отображения). В противном случае разбиение окон ведет себя как для nil.

display-buffer

Это означает, что когда display-buffer (см. Выбор окна для отображения буфера) разбивает окно, он всегда создает новое родительское окно. В противном случае разбиение окон ведет себя как для nil.

t

Это означает, что разбиение окна всегда создает новое родительское окно. Таким образом, если значение этой переменной всегда равно t, то в любой момент каждое дерево окон является бинарным деревом (деревом, где каждое окно, кроме корневого, имеет ровно одного родственного окна).

Значение по умолчанию — window-size. Другие значения зарезервированы для будущего использования.

Если в результате установки этой переменной split-window создает новое родительское окно, он также вызывает set-window-combination-limit (см. ниже) для вновь созданного внутреннего окна. Это влияет на то, как перестраивается дерево окон при удалении дочерних окон (см. ниже).

Если window-combination-limit равно t, разбиение W2 в начальной конфигурации нашего сценария дало бы следующий результат:

     ______________________________________
    | ____________________________________ |
    || __________________________________ ||
    |||                                  |||
    |||________________W2________________|||
    || __________________________________ ||
    |||                                  |||
    |||________________W4________________|||
    ||_________________W5_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W3_________________||
    |__________________W1__________________|

Было создано новое внутреннее окно W5; его дочерними окнами являются W2 и новое живое окно W4. Теперь W2 является единственным родственным окном W4, поэтому увеличение W4 попытается сжать W2, не затрагивая W3. Обратите внимание, что W5 представляет собой вертикальную комбинацию двух окон, вложенную в вертикальную комбинацию W1.

Функция: set-window-combination-limit window limit

Эта функция устанавливает ограничение комбинации окна window в значение limit. Это значение можно получить с помощью функции window-combination-limit. См. ниже о её эффектах; отметим, что она имеет смысл только для внутренних окон. Функция split-window автоматически вызывает эту функцию, передавая ей t в качестве limit, при условии, что значение переменной window-combination-limit равно t в момент её вызова.

Функция: window-combination-limit window

Эта функция возвращает ограничение комбинации для window.

Ограничение комбинации имеет смысл только для внутреннего окна. Если оно равно nil, то Emacs разрешено автоматически удалять window в ответ на удаление окна, чтобы сгруппировать дочерние окна window с его родственными окнами для образования новой комбинации окон. Если ограничение комбинации равно t, дочерние окна window никогда не перекомбинируются автоматически с его родственными окнами.

Если в конфигурации, показанной в начале этого раздела, ограничение комбинации W4 (родительского окна W6 и W7) равно t, удаление W5 не приведёт к неявному удалению W4.

В качестве альтернативы описанные выше проблемы можно избежать, всегда изменяя размер всех окон в одной комбинации всякий раз, когда одно из её окон разбивается или удаляется. Это также позволяет разбивать окна, которые в противном случае были бы слишком малы для такой операции.

Пользовательская опция: window-combination-resize

Если эта переменная равна nil, split-window может разбить окно (обозначаемое как window), только если область экрана window достаточно велика, чтобы вместить и его само, и новое окно.

Если эта переменная равна t, split-window пытается изменить размер всех окон, которые являются частью той же комбинации, что и window, чтобы разместить новое окно. В частности, это может позволить split-window выполнить разбиение, даже если window является окном фиксированного размера или слишком мало для обычного разбиения. Кроме того, последующее изменение размера или удаление window может изменить размер всех остальных окон в его комбинации.

Значение по умолчанию — nil. Другие значения зарезервированы для будущего использования. Конкретная операция разбиения может игнорировать значение этой переменной, если на неё влияет ненулевое значение window-combination-limit.

Чтобы проиллюстрировать эффект window-combination-resize, рассмотрим следующую компоновку кадра.

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W3_________________||
    |__________________W1__________________|

Если window-combination-resize равно nil, разбиение окна W3 оставляет размер W2 неизменным:

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||_________________W3_________________||
    | ____________________________________ |
    ||                                    ||
    ||_________________W4_________________||
    |__________________W1__________________|

Если window-combination-resize равно t, разбиение W3 оставляет все три живых окна примерно с одинаковой высотой:

     ______________________________________
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W2_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W3_________________||
    | ____________________________________ |
    ||                                    ||
    ||                                    ||
    ||_________________W4_________________||
    |__________________W1__________________|

Удаление любого из живых окон W2, W3 или W4 приведёт к пропорциональному распределению его пространства между двумя оставшимися живыми окнами.