;;;; -*- mode:emacs-lisp;coding:utf-8 -*-
(require 'pjb-cl)

;; With Emacs >= 24.1 do either
;;
;; (split-window (frame-root-window))
;;
;; or
;;
;; (split-window (window-parent))


;; Some time ago I wrote some suggestions about how to rewrite
;; balance-windows to use the windows split tree. I have tried to do
;; that. The file bw.el at
;;
;;    http://ourcomments.org/Emacs/DL/elisp/test/
;;
;; contains my rewrite of balance-windows. Could those who are interested
;; please test this version?



;; Since window parents are not normal emacs lisp windows, I'd assume
;; we'd export the window internals as a new data type. Let's call it
;; "split".
;;
;; (frame-split-root [frame])           --> split or nil
;; (window-configuration-split winconf) --> split or nil
;; (splitp object)                      --> boolean
;; (split-direction split)              --> :vertical | :horizontal
;; ;; (window-split-vertically) produces a :vertical split-direction.
;; (split-edges sow)                    --> (left top right bottom)
;; ;; Perhaps (defalias split-edges window-edges)
;; (split-cuts split)                   --> (BReak  BReak  ...)
;; ;; The bottom or right of the correponding child.
;; (split-children split)               --> (child  child  ...)
;; ;; A split child may be a window or a split.
;; (split-parent sow) --> split
;; (enlarge-split sow increment preserve-before)
;;
;;
;; ;; The parent is null for root splits or windows,
;; ;; othewise it's always a split.
;; (or (null   (split-parent sow))
;;     (splitp (split-parent sow)))
;;
;; ;; the edges of the split are the same as the edge of an alone window:
;; (equal (split-edges split) (progn (delete-other-windows) (window-edges)))
;;
;; ;; the length is the number of collapsed windows or splits:
;; (= (length (split-cuts split)) (length (split-children split)))
;;
;; ;; child splits are perpendicular:
;; (every (lambda (child-split)
;;          (not (eq (split-direction split) (split-direction child-split))))
;;        (delete-if-not (function splitp) (split-children split)))
;;
;; ;; split cuts are sorted (hence the order of the corresponding split-children
;; ;; list):
;; (dotimes (i (1- (length (split-cuts split))))
;;   (< (nth i (split-cuts split)) (nth (1+ i) (split-cuts split))))


;; (dotimes (i (length (split-cuts split)))
;;   (and
;;    ;; all children are either a split or a window:
;;    (or (windowp  (nth i (split-children split)))
;;        (splitp   (nth i (split-children split))))
;;    ;; the parent of each children of split is the split itself:
;;    (eq split (split-parent (nth i (split-children split))))
;;    ;; the cuts are the bottom or right of the corresponding child:
;;    (= (nth i (split-cuts split))
;;       (funcall (if (eq (split-direction split) :vertical)
;;                    (function bottom)
;;                    (function right))
;;                (split-edges (nth i (split-children split)))))
;;    ;; the sides are the same for all children:
;;    (every (lambda (side)
;;             (= (funcall side (split-edges split))
;;                (funcall side (split-edges (nth i (split-children split))))))
;;           (if (eq (split-direction split) :vertical)
;;               (list (function left) (function right))
;;               (list (function top)  (function bottom))))
;;    ))
;;
;;
;;
;; Several parallel cuts are collapsed into one split.
;;
;; (progn (delete-other-windows)
;;        (split-window-vertically)
;;        (split-window-vertically))
;;
;; and:
;;
;; (progn (delete-other-windows)
;;        (split-window-vertically)
;;        (other-window 1)
;;        (split-window-vertically))
;;
;; would both give (= 3 (length (split-cuts (frame-split-root)))).
;; And:
;;
;; (equal (progn (delete-other-windows)
;;               (split-window-vertically)
;;               (split-window-vertically)
;;               (frame-split-root))
;;        (progn (delete-other-windows)
;;               (split-window-vertically)
;;               (other-window 1)
;;               (split-window-vertically)
;;               (frame-split-root)))
;;
;;
;;
;; The the balancing algorithm could be:

(defun plusp  (x) (< 0 x))
(defun left   (x) (first  x))
(defun top    (x) (second x))
(defun right  (x) (third  x))
(defun bottom (x) (fourth x))

(defun split-height (split)
  (- (bottom (split-edges split)) (top  (split-edges split))))

(defun split-width  (split)
  (- (right  (split-edges split)) (left (split-edges split))))

(defun balance-split (split)
  (labels ((count-children (sow direction)
             ;; This could be cached into then split-or-window structure
             (if (splitp sow)
                 (reduce (if (eq (split-direction sow) direction)
                             (function +)
                             (function max))
                         (mapcar (lambda (child) (count-children child direction))
                                 (split-children sow)))
                 1)))
    (let* ((relative-sizes
            (mapcar (lambda (child) (count-children child (split-direction split)))
                    (split-children split)))
           (total (reduce (function +) relative-sizes))
           (split-size (if (eq (split-direction split) :vertical)
                           (split-height split)
                           (split-width  split))))
      (loop
         for child-size in relative-sizes
         for child in (butlast (split-children split))
         for new-size = (truncate (* split-size child-size) total)
         do (enlarge-split child
                           (- new-size
                              (if (eq (split-direction split) :vertical)
                                  (split-height child)
                                  (split-width  child)))
                           (split-direction split)
                           t))
      (dolist (child (split-children split))
        (when (splitp child)
          (balance-split child))))))

(defun balance-windows ()
  (interactive)
  (when (splitp (frame-split-root))
    (balance-split (frame-split-root))))













;; The following is a simulator for the above specified split data structure.

(defstruct sow direction parent children right bottom)

(defun split-or-window-previous (sow)
  (let ((parent  (split-or-window-parent sow)))
    (when parent
      (let* ((children (split-or-window-children parent))
             (i (position sow children)))
        (and i (plusp i) (nth (1- i) children))))))

(defun split-or-window-left (sow)
  (let ((parent (split-or-window-parent sow)))
    (if parent
        (if (eq (split-or-window-direction parent) :horizontal)
            (let ((previous (split-or-window-previous sow)))
              (if previous
                  (split-or-window-right previous)
                  (split-or-window-left  parent)))
            (split-or-window-left  parent))
        0)))

(defun split-or-window-top (sow)
  (let ((parent (split-or-window-parent sow)))
    (if parent
        (if (eq (split-or-window-direction parent) :vertical)
            (let ((previous (split-or-window-previous sow)))
              (if previous
                  (split-or-window-bottom previous)
                  (split-or-window-top   parent)))
            (split-or-window-top   parent))
        0)))

(defun splitp (sow)
  (and (split-or-window-p sow)
       (split-or-window-children sow)))

(defun split-edges (sow)
  (list (split-or-window-left sow)
        (split-or-window-top sow)
        (split-or-window-right sow)
        (split-or-window-bottom sow)))

(defun* make-split-or-window (&key right bottom parent children direction)
  (error "Not implemented yet."))

(defvar *current-window*   (make-split-or-window  :right 42 :bottom 42))
(defvar *frame-split-root* *current-window*)
(defun frame-split-root    (&optional frame)  *frame-split-root*)
(defvar *window-list*      (list *current-window*))
(defun window-list*        () *window-list*)
(defun current-window      () *current-window*)

(defun initialize (width height)
  (setf *current-window*    (make-split-or-window  :right width :bottom height)
        *frame-split-root*  *current-window*
        *window-list* (list *current-window*)))

(defun split-direction (split)
  (assert (splitp split))
  (split-or-window-direction split))

(defun split-cuts (split)
  (assert (splitp split))
  (mapcar (if (eq (split-direction split) :vertical)
              (function bottom)
              (function right)) (split-children split)))

(defun split-children (split)
  (assert (splitp split))
  (split-or-window-children split))

(defun split-parent (sow)
  (split-or-window-parent sow))

(defun enlarge-split (sow increment direction preserve-before)
  (unless (zerop increment)
    (if (eq direction :vertical)
        (incf (split-or-window-bottom sow) increment)
        (incf (split-or-window-right  sow) increment))
    (when (splitp sow)
      (if (eq (split-direction sow) direction)
          ;; change the size in same direction
          ;; TODO: check increment vs. last size and preserve-before
          (let ((last-child  (first (last (split-or-window-children
                                           sow)))))
            (enlarge-split last-child increment direction preserve-before))
          ;; change the size orthogonally
          (dolist (child (split-or-window-children sow))
            (enlarge-split child increment direction preserve-before))))
    (let ((parent (split-or-window-parent sow)))
      (when (and parent (eq (split-direction parent) direction))
        (let ((next (second (memq sow (split-or-window-children parent)))))
          (when next
            (if (eq direction :vertical)
                (incf (split-or-window-top  next) increment)
                (incf (split-or-window-left next) increment))))))))

(defun insert-after (new old list) (push new (cdr (memq old list))))

(defun split (direction &optional size)
  (flet ((split-size (split) (if (eq direction :vertical)
                                 (split-height split)
                                 (split-width  split)))
         (make-split (direction window parent)
           (let* ((edges (split-edges window))
                  (result (make-split-or-window
                           :parent parent
                           :children (list window)
                           :direction direction
                           :right  (right  edges)
                           :bottom (bottom edges))))
             (setf (split-or-window-parent window) result))))
    (setf size (or size (/ (split-size (current-window)) 2)))
    (unless (< 1 size)
      (error  "split: Window too small."))
    (when (<= (split-size (current-window)) size)
      (error "split: Too big size asked."))
    (let ((split (split-parent (current-window))))
      (cond
        ((null split)
         ;; make a new root split:
         (setf split (make-split direction (current-window) nil))
         (setf *frame-split-root* split))
        ((not (eq direction (split-direction split)))
         ;; make a new perpendicular split
         (let ((perpendicular (make-split direction (current-window) split)))
           (setf (split-or-window-children split)
                 (nsubstitute perpendicular (current-window)
                              (split-or-window-children split)))
           (assert (memq perpendicular (split-or-window-children split)))
           (setf split perpendicular))))
      (assert (eq split (split-parent (current-window))))
      (assert (memq (current-window) (split-children split)))
      (assert (eq direction (split-direction split)))
      (let* ((dx (if (eq direction :vertical) 0 size))
             (dy (if (eq direction :vertical) size 0))
             (edges (split-edges (current-window)))
             ;; make a new window:
             (other (make-split-or-window
                     :parent split
                     :right  (right  edges)
                     :bottom (bottom edges))))
        (if (eq direction :vertical)
            (setf (split-or-window-bottom (current-window)) (+ (top  edges) dy))
            (setf (split-or-window-right (current-window))  (+ (left edges) dx)))
        (insert-after other (current-window) (split-or-window-children split))
        (insert-after other (current-window) *window-list*)
        (assert (memq (current-window) *window-list*))
        (assert (memq other            *window-list*))
        (assert (memq (current-window) (split-or-window-children split)))
        (assert (memq other            (split-or-window-children split)))))))

(defun other-window* (n &optional all-frames)
  (let ((i (mod (+ (position (current-window) (window-list*)) n)
                (length (window-list*)))))
    (setf *current-window* (nth i (window-list*)))))

(defun windowp* (window) (memq window (window-list*)))

(defun delete-other-windows* (&optional window)
  (when (windowp* window)
    (setf *current-window* window))
  (setf window (current-window))
  (when (split-parent window)
    (let ((root  (frame-split-root)))
      (setf (split-or-window-left   window) (split-or-window-left   root)
            (split-or-window-top    window) (split-or-window-top    root)
            (split-or-window-right  window) (split-or-window-right  root)
            (split-or-window-bottom window) (split-or-window-bottom root)))
    (setf (split-or-window-parent window) nil)
    (setf *frame-split-root* window
          *window-list* (list window))))

(defun split-describe (split &optional level)
  (setf level (or level ""))
  (if (splitp split)
      (progn
        (insert (format "%s#<split %s %s %s %s>\n"
                  level
                  (format ":direction %S" (split-direction split))
                  (format ":parent %S" (not (null (split-parent split))))
                  (format ":edges %S" (split-edges split))
                  (format ":children %S" (length (split-children split)))))
        (dolist (child (split-children split))
          (split-describe child (concat "  " level))))
      (insert (format "%s#<window %s %s>\n"
                level
                (format ":parent %S" (not (null (split-parent split))))
                (format ":edges %S" (split-edges split))))))

(defun split-draw (split)
  (with-current-buffer (get-buffer-create "*splits*")
    (erase-buffer)
    (unless (eq major-mode 'picture-mode)
      (picture-mode))
    (picture-open-line (1+ (bottom (split-edges split))))
    (labels ((goto (x y)
               (message "goto %s %s" x y)
               (goto-line y)
               (beginning-of-line)
               (picture-forward-column x))
             (draw-rectangle (edges)
               (picture-draw-rectangle
                (progn (goto (left  edges) (top    edges)) (point))
                (progn (goto (right edges) (bottom edges)) (point))))
             (draw-split (split)
               (draw-rectangle (split-edges split))
               (if (splitp split)
                   (dolist (child (split-children split))
                     (draw-split child)))))
      (draw-split split)))
  (sit-for 1)
  (force-mode-line-update t))


(progn
  (initialize 60 56)
  (delete-other-windows*)
  (split :vertical)
  (split :horizontal)
  (split :vertical)
  (split :vertical)
  (balance-windows) (split-draw (frame-split-root))
  (other-window* 4)
  (split :vertical)
  (split :horizontal)
  (split :horizontal)
  (other-window* 1)
  (split :vertical)
  (balance-windows) (split-draw (frame-split-root))
  (other-window* 7)
  (split :vertical)
  (split :vertical)
  (split :vertical)
  (balance-windows) (split-draw (frame-split-root))
  (split-describe (frame-split-root)))


;; #<split :direction :vertical :parent nil :edges (0 0 60 56) :children 3>
;;   #<split :direction :horizontal :parent t :edges (0 0 60 32) :children 2>
;;     #<split :direction :vertical :parent t :edges (0 0 30 32) :children 3>
;;       #<window :parent t :edges (0 0 30 10)>
;;       #<window :parent t :edges (0 10 30 20)>
;;       #<window :parent t :edges (0 20 30 32)>
;;     #<split :direction :vertical :parent t :edges (30 0 60 32) :children 4>
;;       #<window :parent t :edges (30 0 60 8)>
;;       #<window :parent t :edges (30 8 60 16)>
;;       #<window :parent t :edges (30 16 60 24)>
;;       #<window :parent t :edges (30 24 60 32)>
;;   #<split :direction :horizontal :parent t :edges (0 32 60 48) :children 3>
;;     #<window :parent t :edges (0 32 20 48)>
;;     #<split :direction :vertical :parent t :edges (20 32 40 48) :children 2>
;;       #<window :parent t :edges (20 32 40 40)>
;;       #<window :parent t :edges (20 40 40 48)>
;;     #<window :parent t :edges (40 32 60 48)>
;;   #<window :parent t :edges (0 48 60 56)>
;;
;;
;; +-----------------------------+-----------------------------+
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             +-----------------------------+
;; |                             |                             |
;; +-----------------------------|                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             +-----------------------------+
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; +-----------------------------|                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             +-----------------------------+
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; |                             |                             |
;; +-------------------+-------------------+-------------------+
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   +-------------------|                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; |                   |                   |                   |
;; +-----------------------------------------------------------+
;; |                                                           |
;; |                                                           |
;; |                                                           |
;; |                                                           |
;; |                                                           |
;; |                                                           |
;; |                                                           |
;; +-----------------------------------------------------------+

(frame-list)
(#<frame emacs: pjb@thalassa 0x919a6b0> #<frame PGM 0x8607cc0>)
(mapcar (function window-edges) (window-list))



(mapcar (function window-edges)
        (window-list (first (frame-list)) nil
                     (frame-first-window (first (frame-list)))))


(defstruct (pt (:type list)) x y)

(defun pt-of-edges (edges)
  (list
   (make-pt :x (left  edges) :y (top    edges))
   (make-pt :x (left  edges) :y (bottom edges))
   (make-pt :x (right edges) :y (top    edges))
   (make-pt :x (right edges) :y (bottom edges))))



(defun plusp  (x) (< 0 x))
(defun left   (x) (first  x))
(defun top    (x) (second x))
(defun right  (x) (third  x))
(defun bottom (x) (fourth x))


(defalias 'current-frame  'selected-frame)
(defalias 'current-window 'selected-window)

(defstruct sow* parent left top right bottom)
(defstruct (window* (:include sow*)) window)
(defstruct (split*  (:include sow*)) direction children)

(defun window* (window)
  (let ((edges (window-edges window)))
    (make-window* :window window
                  :left   (left   edges)
                  :right  (right  edges)
                  :top    (top    edges)
                  :bottom (bottom edges))))

(defun window*-list (&optional frame)
  (setf frame (or frame  (current-frame)))
  (mapcar (function window*)
          (window-list frame nil (frame-first-window frame))))

(defun split*-edges (sow)
  (etypecase sow
    (window  (window-edges sow))
    (window* (list (window*-left  sow) (window*-top    sow)
                   (window*-right sow) (window*-bottom sow)))
    (split*  (list (split*-left    sow) (split*-top      sow)
                   (split*-right   sow) (split*-bottom   sow)))))

(defun split*-height (split)
  (- (bottom (split*-edges split)) (top  (split*-edges split))))

(defun split*-width  (split)
  (- (right  (split*-edges split)) (left (split*-edges split))))

(defun boxes-match-sides (a b)
  (cond
    ((and (= (right  a) (left   b))
          (= (top    a) (top    b))
          (= (bottom a) (bottom b))) :on-the-right)
    ((and (= (right  b) (left   a))
          (= (top    b) (top    a))
          (= (bottom b) (bottom a))) :on-the-left)
    ((and (= (bottom a) (top    b))
          (= (left   a) (left   b))
          (= (right  a) (right  b))) :over)
    ((and (= (bottom b) (top    a))
          (= (left   b) (left   a))
          (= (right  b) (right  a))) :under)
    (t nil)))


(defun symetric-side (x)
  (ecase x
    (:on-the-right :on-the-left)
    (:on-the-left  :on-the-right)
    (:over         :under)
    (:under        :over)))

(defun orthogonal-sides-p (a b)
  (ecase a
    ((:on-the-right :on-the-left)  (ecase b
                                     ((:on-the-right :on-the-left) nil)
                                     ((:over         :under)       t)))
    ((:over         :under)        (ecase b
                                     ((:on-the-right :on-the-left) t)
                                     ((:over         :under)       nil)))))



(defun more-than-one-p (set) (cdr set))
(defun choose&extract (set) (values (first set) (rest set) set))
(defun* find&extract   (item set &key (test (function eql)))
  (let ((index (position item set :test test :key key)))
    (cond
      ((null index)  (values nil set nil))
      ((zerop index) (values (first set) (rest set) t))
      (t             (values (nth index set)
                             (delete-if (constantly t) set
                                        :start index :end (1+ index))
                             t)))))

(defun make-chainlet    (list)   (cons list (last list)))
(defun chainlet-list    (c) (car c))
(defun chainlet-tail    (c) (cdr c))
(defun chainlet-first   (c) (caar c))
(defun chainlet-last    (c) (cadr c))
(defun chainlet-match-p (c d) (eql (cadr c) (caar d)))
(defun nchainlet-join   (c d) (setf (cddr c) (cdar d)  (cdr c) (cdr d)) c)
(defun chain-lists (lists)
  (loop
     with changed = t
     with chainlets = (mapcar (function make-chainlet) lists)
     while changed
     do (setf changed nil)
     (loop
        with new-chainlets = '()
        while (more-than-one-p chainlets)
        do (multiple-value-bind (current rest) (choose&extract chainlets)
             (multiple-value-bind (next rest gotit)
                 (find&extract current rest :test (function chainlet-match-p))
               (if gotit
                   (progn
                     (push (nchainlet-join current next) new-chainlets)
                     (setf changed   t))
                   (push current new-chainlets))
               (setf chainlets rest)))
        finally (setf chainlets (append chainlets new-chainlets)))
     finally (return (mapcar (function chainlet-list) chainlets))))


(defun group-sows (sows)
  (flet ((collect-sides (windows edges)
           (loop
              for wl on windows
              for el on edges
              nconc (loop
                       with wina = (car wl)
                       with edga = (car el)
                       for winb in (cdr wl)
                       for edgb in (cdr el)
                       for side = (boxes-match-sides edga edgb)
                       when side collect (list wina side winb)
                       when side collect (list winb (symetric-side side)
                                               wina)))))
    (let ((sides
           (loop
              with sow = sows
              for edges = (mapcar (function split*-edges) sow)
              for sides = (collect-sides sow edges)
              for ww = (make-hash-table)
              while (block :body
                      (dolist (side sides)
                        (let ((w (gethash (first side) ww)))
                          (if (and w (orthogonal-sides-p w (second side)))
                              (let ((win  (first side)))
                                (with-selected-window (window*-window win)
                                  (enlarge-window
                                   (if (< (split*-height win) 2) 1 -1) nil)
                                  (enlarge-window
                                   (if (< (split*-width  win) 2) 1 -1) t))
                                (return-from :body t))
                              (setf (gethash (first side) ww) (second side))
                              nil))))
              finally (return sides))))
      (delete-if (lambda (side) (memq (second side) '(:under :on-the-left))) sides))))

(defun frame-split-root (&optional frame)
  (setf frame (or frame (current-frame)))
  (flet ((ensplit (children direction)
           (let* ((edges (mapcar (function split*-edges) children))
                  (split (make-split*
                          :children  children
                          :direction direction
                          :left    (reduce (function min)
                                           (mapcar (function left) edges))
                          :right   (reduce (function max)
                                           (mapcar (function right) edges))
                          :top     (reduce (function min)
                                           (mapcar (function top) edges))
                          :bottom  (reduce (function max)
                                           (mapcar (function bottom) edges)))))
             (dolist (child children)
               (setf (sow*-parent child) split))
             split)))
    (loop
       with sows = (window*-list frame)
       while (more-than-one-p sows)
       do (multiple-value-bind (horizontal vertical)
              (loop
                 with groups = (group-sows sows)
                 with horizontal = '()
                 with vertical   = '()
                 for group in groups
                 ;; Note: we keep emacs meaning for horizontal and vertical!
                 do (if (eq (verb group) :over)
                        (push (list (first group) (third group)) horizontal)
                        (push (list (first group) (third group)) vertical))
                 finally (return (values horizontal vertical)))
            (setf horizontal (chain-lists horizontal)
                  vertical   (chain-lists vertical)
                  sows (nconc
                        (mapcar (lambda (children) (ensplit children :horizontal))
                                horizontal)
                        (mapcar (lambda (children) (ensplit children :vertical))
                                vertical)))
            (print sows))
       finally (return (car sows)))))

(defun split-describe (split &optional level)
  (setf level (or level ""))
  (etypecase split
    (null (insert (format "%snil\n" level)))
    (split*
     (insert (format "%s#<split %s %s %s %s>\n"
               level
               (format ":direction %S" (split*-direction split))
               (format ":parent %S" (not (null (split*-parent split))))
               (format ":edges %S" (split*-edges split))
               (format ":children %S" (length (split*-children split)))))
     (dolist (child (split*-children split))
       (split-describe child (concat "  " level))))
    (window*
     (insert (format "%s#<window %s %s>\n"
               level
               (format ":parent %S" (not (null (window*-parent split))))
               (format ":edges %S" (split*-edges split)))))))



(split-describe (frame-split-root))

(#1=[cl-struct-split* nil 0 0 40 20 :horizontal ([cl-struct-window* #1# 0 0 40 13 #<window 141 on split.el>] #2=[cl-struct-window* #3=[cl-struct-split* nil 0 13 40 27 :horizontal (#2# [cl-struct-window* #3# 0 20 40 27 #<window 142 on split.el>])] 0 13 40 20 #<window 140 on split.el>])] #3# #4=[cl-struct-split* nil 40 0 86 13 :horizontal ([cl-struct-window* #4# 40 0 86 6 #<window 138 on split.el>] #5=[cl-struct-window* #6=[cl-struct-split* nil 40 6 86 27 :horizontal (#5# [cl-struct-window* #6# 40 13 86 27 #<window 144 on split.el>])] 40 6 86 13 #<window 145 on split.el>])] #6# #7=[cl-struct-split* nil 0 27 86 55 :horizontal ([cl-struct-window* #7# 0 27 86 41 #<window 136 on split.el>] [cl-struct-window* #7# 0 41 86 55 #<window 146 on split.el>])])

nil
nil
nil


(group-sows (window*-list))
(setf sows  (window*-list))

(chain-lists '((1 2) (2 3) (a b) (3 4) (d e) (c d) (aa bb) (cc dd)))

(setf c (make-chainlet (list 1 2))
      d (make-chainlet (list 2 3)))
(chainlet-match-p c d)
(nchainlet-join c d)
ViewGit