Prefira divisões verticais em relação às horizontais

9

Existem várias perguntas semelhantes a esta. Eu li todos eles e eles não fornecem uma resposta para o meu cenário. Quero que o emacs prefira divisões verticais (janelas divididas em partes esquerda e direita) em vez de horizontais, mesmo que seja possível a divisão horizontal e vertical . Isto é o que o manual diz:

A divisão pode ser vertical ou horizontal, dependendo das variáveis ​​limite da altura da divisão e limite da largura da divisão. Essas variáveis ​​devem ter valores inteiros. Se o limite da altura da divisão for menor que a altura da janela escolhida, a divisão colocará a nova janela abaixo. Caso contrário, se o limite da largura da divisão for menor que a largura da janela, a divisão colocará a nova janela à direita.

Portanto, se ambos split-height-thresholde split-width-thresholdforem menores que a largura e altura da janela, o emacs executará uma divisão horizontal. Eu quero o oposto Se os dois limites forem menores, execute uma divisão vertical.

Uma maneira de conseguir isto é conjunto split-height-thresholdpara nil, mas eu não gosto disso porque ele desativa divisão horizontal completamente.

Eu olhei para a split-window-sensiblyfunção, mas não sou bom o suficiente no elisp para escrever minha própria my-split-window-sensiblyfunção que funciona como eu quero.

Björn Lindqvist
fonte
Há uma variável chamada split-window-preferred-functionque pode ser configurada para usar uma função personalizada. Dê uma boa olhada na função split-window-sensiblye veja se ela pode atender às suas necessidades, ajustando determinadas variáveis, como você mencionou na sua pergunta, e também leia a sequência de documentos dessa função ... se ela não puder ser feita para atender às suas necessidades, então você pode escrever outro, ou obter ajuda para escrever outra função ...
lawlist

Respostas:

5

Na minha experiência, esse é um problema mais difícil que se possa pensar, porque a idéia intuitiva do que é sensível nem sempre é fácil de colocar em termos precisos. Vou apenas descrever o que acabei, mas você pode ter que mexer.

Primeiro: a split-window-sensiblyfunção existente sempre prefere terminar com uma pilha horizontal de janelas (que, de maneira confusa, chama uma "divisão" vertical, embora a divisão seja horizontal ...) em um arranjo lado a lado. É fácil criar uma função que tenha a preferência oposta, que é essencialmente apenas uma cópia split-window-sensiblycom as preferências invertidas:

(defun split-window-sensibly-prefer-horizontal (&optional window)
"Based on split-window-sensibly, but designed to prefer a horizontal split,
i.e. windows tiled side-by-side."
  (let ((window (or window (selected-window))))
    (or (and (window-splittable-p window t)
         ;; Split window horizontally
         (with-selected-window window
           (split-window-right)))
    (and (window-splittable-p window)
         ;; Split window vertically
         (with-selected-window window
           (split-window-below)))
    (and
         ;; If WINDOW is the only usable window on its frame (it is
         ;; the only one or, not being the only one, all the other
         ;; ones are dedicated) and is not the minibuffer window, try
         ;; to split it horizontally disregarding the value of
         ;; `split-height-threshold'.
         (let ((frame (window-frame window)))
           (or
            (eq window (frame-root-window frame))
            (catch 'done
              (walk-window-tree (lambda (w)
                                  (unless (or (eq w window)
                                              (window-dedicated-p w))
                                    (throw 'done nil)))
                                frame)
              t)))
     (not (window-minibuffer-p window))
     (let ((split-width-threshold 0))
       (when (window-splittable-p window t)
         (with-selected-window window
               (split-window-right))))))))

Portanto, agora temos duas funções: a original que "prefere" uma pilha vertical e a nova que "prefere" uma pilha horizontal.

Em seguida, precisamos de uma função que tende a preferir a que preferimos usar.

(defun split-window-really-sensibly (&optional window)
  (let ((window (or window (selected-window))))
    (if (> (window-total-width window) (* 2 (window-total-height window)))
        (with-selected-window window (split-window-sensibly-prefer-horizontal window))
      (with-selected-window window (split-window-sensibly window)))))

Você precisa mexer nos valores aqui, mas a idéia básica é que preferimos um arranjo vertical sempre que houver pelo menos o dobro da largura e da altura. Você pode pensar que queria onde a janela existente é mais larga do que alta, mas, na minha experiência, isso não está certo e permite que você termine com janelas muito finas.

Finalmente, também precisamos ter alguns mínimos sãos. Defino um split-height-thresholdde 4 (ou seja, não quero, a menos que seja inevitável, ter menos de 2 linhas em uma janela) e um split-width-thresholdde 40 (ou seja, eu não quero, a menos que seja inevitável, ter menos de 20 caracteres numa janela) - pelo menos acho que é isso que isso significa.

Então se liga split-window-preferred-functionasplit-window-really-sensibly

(setq
   split-height-threshold 4
   split-width-threshold 40 
   split-window-preferred-function 'split-window-really-sensibly)

Outra idéia (que você pode preferir) seria apenas substituir a disposição "preferência por lado a lado" e definida split-width-thresholdcomo 80: então você teria janelas lado a lado sempre que houvesse espaço para elas, eu acho.

Paul Stanley
fonte
11
Funciona! Mas eu tive que manter os split-height/width-thresholdvalores em seu padrão ou a pop-to-bufferfunção criaria novas divisões em vez de reutilizar as antigas. Eu prefiro ter uma única divisão direita / esquerda e não quero que as funções do emacs mexam com isso.
Björn Lindqvist
1

Você pode usar meu pacote el-patchpara implementar a função split-window-sensibly-prefer-horizontalde uma maneira que torne óbvio o que foi alterado em relação ao original split-window-sensiblye também permita que você detecte se a definição original é alterada em uma versão futura do Emacs:

(el-patch-defun (el-patch-swap
                  split-window-sensibly
                  split-window-sensibly-prefer-horizontal)
  (&optional window)
  "Split WINDOW in a way suitable for `display-buffer'.
WINDOW defaults to the currently selected window.
If `split-height-threshold' specifies an integer, WINDOW is at
least `split-height-threshold' lines tall and can be split
vertically, split WINDOW into two windows one above the other and
return the lower window.  Otherwise, if `split-width-threshold'
specifies an integer, WINDOW is at least `split-width-threshold'
columns wide and can be split horizontally, split WINDOW into two
windows side by side and return the window on the right.  If this
can't be done either and WINDOW is the only window on its frame,
try to split WINDOW vertically disregarding any value specified
by `split-height-threshold'.  If that succeeds, return the lower
window.  Return nil otherwise.

By default `display-buffer' routines call this function to split
the largest or least recently used window.  To change the default
customize the option `split-window-preferred-function'.

You can enforce this function to not split WINDOW horizontally,
by setting (or binding) the variable `split-width-threshold' to
nil.  If, in addition, you set `split-height-threshold' to zero,
chances increase that this function does split WINDOW vertically.

In order to not split WINDOW vertically, set (or bind) the
variable `split-height-threshold' to nil.  Additionally, you can
set `split-width-threshold' to zero to make a horizontal split
more likely to occur.

Have a look at the function `window-splittable-p' if you want to
know how `split-window-sensibly' determines whether WINDOW can be
split."
  (let ((window (or window (selected-window))))
    (or (el-patch-let
            (($fst (and (window-splittable-p window)
                        ;; Split window vertically.
                        (with-selected-window window
                          (split-window-below))))
             ($snd (and (window-splittable-p window t)
                        ;; Split window horizontally.
                        (with-selected-window window
                          (split-window-right)))))
          (el-patch-swap $fst $snd)
          (el-patch-swap $snd $fst))
        (and
         ;; If WINDOW is the only usable window on its frame (it
         ;; is the only one or, not being the only one, all the
         ;; other ones are dedicated) and is not the minibuffer
         ;; window, try to split it s/vertically/horizontally
         ;; disregarding the value of `split-height-threshold'.
         (let ((frame (window-frame window)))
           (or
            (eq window (frame-root-window frame))
            (catch 'done
              (walk-window-tree (lambda (w)
                                  (unless (or (eq w window)
                                              (window-dedicated-p w))
                                    (throw 'done nil)))
                                frame)
              t)))
         (not (window-minibuffer-p window))
         (let (((el-patch-swap split-height-threshold
                               split-width-threshold)
                0))
           (when (window-splittable-p window)
             (with-selected-window window
               ((el-patch-swap split-window-below split-window-right)))))))))
Radon Rosborough
fonte
1

Encontrei esta solução na lista de distribuição do Emacs e faz maravilhas:

;; Fix annoying vertical window splitting.
;; https://lists.gnu.org/archive/html/help-gnu-emacs/2015-08/msg00339.html
(with-eval-after-load "window"
  (defcustom split-window-below nil
    "If non-nil, vertical splits produce new windows below."
    :group 'windows
    :type 'boolean)

  (defcustom split-window-right nil
    "If non-nil, horizontal splits produce new windows to the right."
    :group 'windows
    :type 'boolean)

  (fmakunbound #'split-window-sensibly)

  (defun split-window-sensibly
      (&optional window)
    (setq window (or window (selected-window)))
    (or (and (window-splittable-p window t)
             ;; Split window horizontally.
             (split-window window nil (if split-window-right 'left  'right)))
        (and (window-splittable-p window)
             ;; Split window vertically.
             (split-window window nil (if split-window-below 'above 'below)))
        (and (eq window (frame-root-window (window-frame window)))
             (not (window-minibuffer-p window))
             ;; If WINDOW is the only window on its frame and is not the
             ;; minibuffer window, try to split it horizontally disregarding the
             ;; value of `split-width-threshold'.
             (let ((split-width-threshold 0))
               (when (window-splittable-p window t)
                 (split-window window nil (if split-window-right
                                              'left
                                            'right))))))))

(setq-default split-height-threshold  4
              split-width-threshold   160) ; the reasonable limit for horizontal splits

Parabéns a Alexander, o autor original.

dangom
fonte