Thích chia tách dọc hơn các phân chia ngang


9

Có một số câu hỏi tương tự như câu hỏi này. Tôi đã đọc tất cả và họ không cung cấp câu trả lời cho kịch bản của tôi. Tôi muốn emacs thích chia tách dọc (chia cửa sổ thành các phần bên trái và bên phải) so với các phần ngang, ngay cả khi có thể chia cả ngang và dọc . Đây là những gì hướng dẫn nói:

Sự phân chia có thể theo chiều dọc hoặc chiều ngang, tùy thuộc vào các biến chia ngưỡng chiều cao và ngưỡng chia chiều rộng. Các biến này nên có giá trị nguyên. Nếu ngưỡng chia chiều cao nhỏ hơn chiều cao của cửa sổ đã chọn, thì phần tách sẽ đặt cửa sổ mới bên dưới. Mặt khác, nếu ngưỡng chia chiều rộng nhỏ hơn chiều rộng của cửa sổ, thì phần tách sẽ đặt cửa sổ mới ở bên phải.

Vì vậy, nếu cả hai split-height-thresholdsplit-width-thresholdnhỏ hơn chiều rộng và chiều cao của cửa sổ, emacs sẽ thực hiện phân chia ngang. Tôi muốn điều ngược lại. Nếu cả hai ngưỡng nhỏ hơn, thực hiện phân chia dọc.

Một cách để đạt được điều đó là để thiết lập split-height-thresholdđể nil, nhưng tôi không thích điều đó bởi vì nó vô hiệu hóa tách ngang hoàn toàn.

Tôi đã xem xét split-window-sensiblyhàm, nhưng tôi không đủ giỏi để viết my-split-window-sensiblyhàm riêng của mình hoạt động như tôi muốn.


Có một biến được gọi là split-window-preferred-functioncó thể được thiết lập để sử dụng một chức năng tùy chỉnh. Có một cái nhìn tốt về chức năng split-window-sensiblyvà xem liệu nó có thể phù hợp với nhu cầu của bạn hay không bằng cách điều chỉnh các biến nhất định như bạn đã đề cập trong câu hỏi của mình và cũng đọc chuỗi doc của hàm đó ... nếu nó không thể được thực hiện phù hợp với nhu cầu của bạn, thì bạn có thể viết một cái khác, hoặc nhờ trợ giúp viết một chức năng khác ...
luật

Câu trả lời:


5

Theo kinh nghiệm của tôi, đây là một vấn đề khó hơn mà người ta có thể nghĩ, bởi vì ý tưởng trực quan của một người về những gì hợp lý không phải lúc nào cũng dễ dàng đưa ra những thuật ngữ chính xác. Tôi sẽ chỉ mô tả những gì tôi đã kết thúc, nhưng bạn có thể phải loay hoay.

Đầu tiên: split-window-sensiblyhàm hiện có luôn thích kết thúc với một chồng các cửa sổ nằm ngang (mà khá khó hiểu, nó gọi là "chia" dọc, mặc dù phần tách là nằm ngang ...) trên một bố trí cạnh nhau. Thật dễ dàng để tạo ra một chức năng có sở thích ngược lại, về cơ bản chỉ là một bản sao split-window-sensiblyvới các sở thích được đảo ngược:

(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))))))))

Vì vậy, bây giờ chúng ta có hai chức năng: bản gốc "thích" một ngăn xếp dọc và một chức năng mới "thích" một ngăn xếp ngang.

Tiếp theo, chúng ta cần một chức năng có xu hướng thích cái mà chúng ta muốn sử dụng.

(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)))))

Bạn cần phải xoay quanh các giá trị ở đây, nhưng ý tưởng cơ bản là chúng tôi thích sắp xếp theo chiều dọc bất cứ khi nào có chiều rộng ít nhất gấp đôi chiều cao. Bạn có thể nghĩ rằng bạn muốn nó ở bất cứ nơi nào cửa sổ hiện tại rộng hơn chiều cao của nó, nhưng theo kinh nghiệm của tôi thì không đúng, và cho phép bạn kết thúc với các cửa sổ quá mỏng.

Cuối cùng, chúng ta cũng cần phải có một số mức tối thiểu lành mạnh. Tôi đặt một split-height-thresholdtrong 4 (tức là tôi không muốn, trừ khi không thể tránh khỏi, có ít hơn 2 dòng trong một cửa sổ) và split-width-threshold40 (nghĩa là tôi không muốn, trừ khi không thể tránh khỏi, có ít hơn 20 ký tự trong một cửa sổ) - ít nhất tôi nghĩ đó là những gì có nghĩa.

Sau đó, người ta chỉ liên kết split-window-preferred-functionvớisplit-window-really-sensibly

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

Một ý tưởng khác (mà bạn có thể thích) sẽ chỉ là thay thế sự sắp xếp "ưu tiên cho việc bên cạnh" và được đặt split-width-thresholdthành 80: sau đó bạn sẽ có được các cửa sổ cạnh nhau bất cứ khi nào có không gian cho chúng, tôi nghĩ vậy.


1
Nó hoạt động! Nhưng tôi phải giữ các split-height/width-thresholdgiá trị theo mặc định của chúng, nếu không thì pop-to-bufferhàm sẽ tạo ra các phần tách mới thay vì sử dụng lại các giá trị cũ. Tôi thích có một phân chia phải / trái duy nhất và không muốn các hàm emacs gây rối với điều đó.
Bjorn Lindqvist

1

Bạn có thể sử dụng gói của tôi el-patchđể triển khai chức năng split-window-sensibly-prefer-horizontaltheo cách làm rõ ràng những gì đã thay đổi so với ban đầu split-window-sensiblyvà cũng cho phép bạn phát hiện nếu định nghĩa ban đầu thay đổi trong bản phát hành Emacs trong tương lai:

(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)))))))))

1

Tôi tìm thấy giải pháp này trong danh sách gửi thư của Emacs và nó hoạt động rất tuyệt vời:

;; 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

Kudos cho Alexander, tác giả ban đầu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.