branch: externals/taxy commit 0826a47a19a05c556881a10c3067167accb0a1b8 Author: Adam Porter <a...@alphapapa.net> Commit: Adam Porter <a...@alphapapa.net>
WIP: taxy-magit-section column/table formatting --- taxy-magit-section.el | 73 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/taxy-magit-section.el b/taxy-magit-section.el index 49a573a..1532918 100644 --- a/taxy-magit-section.el +++ b/taxy-magit-section.el @@ -32,8 +32,14 @@ ;;;; Variables -(defvar taxy-magit-section-indent 2 - "Default indentation per level.") +(defvar taxy-magit-section-heading-indent 2 + "Default heading indentation per level.") + +(defvar taxy-magit-section-item-indent 2 + "Default item indentation per level.") + +(defvar taxy-magit-section-depth nil + "Bound to current depth around calls to a taxy's format-fn.") ;;;; Customization @@ -58,8 +64,9 @@ ;; inheritance easier (and/or use EIEIO, but that would reduce ;; performance, since slot accessors can't be optimized). (visibility-fn #'taxy-magit-section-visibility) - (heading-face (lambda (_depth) 'magit-section-heading)) - (indent 2) + (heading-face-fn (lambda (_depth) 'magit-section-heading)) + (heading-indent 2) + (item-indent 2) format-fn) ;;;; Commands @@ -88,10 +95,11 @@ which blank lines are inserted between sections at that level." ;; something was wrong about the properties, and ;; `magit-section' didn't navigate the sections ;; properly anymore. - (let* ((formatted (funcall format-fn item)) + (let* ((taxy-magit-section-depth depth) + (formatted (funcall format-fn item)) (indent-size (pcase depth ((pred (> 0)) 0) - (_ (* depth taxy-magit-section-indent)))) + (_ (* depth taxy-magit-section-item-indent)))) (indent-string (make-string indent-size ? ))) (add-text-properties 0 (length indent-string) (text-properties-at 0 formatted) @@ -103,7 +111,8 @@ which blank lines are inserted between sections at that level." (taxy-magit-section (taxy-magit-section-format-fn taxy)) (t (lambda (o) (format "%s" o))))) - (taxy-magit-section-indent (taxy-magit-section-indent taxy))) + (taxy-magit-section-heading-indent (taxy-magit-section-heading-indent taxy)) + (taxy-magit-section-item-indent (taxy-magit-section-item-indent taxy))) (cl-typecase taxy (taxy-magit-section (when (taxy-magit-section-visibility-fn taxy) @@ -113,9 +122,9 @@ which blank lines are inserted between sections at that level." (make-string (* (pcase depth ((pred (> 0)) 0) (_ depth)) - (taxy-magit-section-indent taxy)) ? ) + (taxy-magit-section-heading-indent taxy)) ? ) (propertize (taxy-name taxy) - 'face (funcall (taxy-magit-section-heading-face taxy) depth)) + 'face (funcall (taxy-magit-section-heading-face-fn taxy) depth)) (format " (%s%s)" (if (taxy-description taxy) (concat (taxy-description taxy) " ") @@ -124,12 +133,12 @@ which blank lines are inserted between sections at that level." (magit-insert-section-body (when (eq 'first items) (dolist (item (taxy-items taxy)) - (insert-item item format-fn depth))) + (insert-item item format-fn (1+ depth)))) (dolist (taxy (taxy-taxys taxy)) (insert-taxy taxy (1+ depth))) (when (eq 'last items) (dolist (item (taxy-items taxy)) - (insert-item item format-fn depth)))) + (insert-item item format-fn (1+ depth))))) (when (<= depth blank-between-depth) (insert "\n")))))) (magit-insert-section (magit-section) @@ -155,6 +164,48 @@ Default visibility function for (_ 'show))) (_ nil))) +(defun taxy-magit-section-format-items (columns formatters taxy) + "Return a cons (table . column-sizes) for COLUMNS, FORMATTERS, and TAXY. +COLUMNS is a list of column names, each of which should have an +associated formatting function in FORMATTERS. + +Table is a hash table keyed by item whose values are display +strings. Column-sizes is an alist whose keys are column names +and values are the column width. Each string is formatted +according to `columns' and takes into account the width of all +the items' values for each column." + (let ((table (make-hash-table)) + column-sizes) + (cl-labels ((format-column + (item depth column-name) + (let* ((fn (alist-get column-name formatters nil nil #'equal)) + (value (funcall fn item depth)) + (current-column-size (or (map-elt column-sizes column-name) 0))) + (setf (map-elt column-sizes column-name) + (max current-column-size (1+ (length (format "%s" value))))) + value)) + (format-item + (depth item) (puthash item + (cl-loop for column in columns + collect (format-column item depth column)) + table)) + (format-taxy (depth taxy) + (dolist (item (taxy-items taxy)) + (format-item depth item)) + (dolist (taxy (taxy-taxys taxy)) + (format-taxy (1+ depth) taxy)))) + (format-taxy 0 taxy) + ;; Now format each item's string using the column sizes. + (let* ((column-sizes (nreverse column-sizes)) + (format-string (string-join (cl-loop for (_name . size) in column-sizes + collect (format "%%-%ss" size)) + " "))) + (maphash (lambda (item column-values) + (puthash item (apply #'format format-string column-values) + table)) + table) + (cons table column-sizes))))) + ;;;; Footer (provide 'taxy-magit-section)