Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor using map-let, reformat #1

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 88 additions & 75 deletions grid.el
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@
;;; Code:

(require 'subr-x)
(require 'map)

(defvar grid-margin 1)

(defun grid-content-empty-p (box)
(defun grid-content-not-empty-p (box)
"Non-nil if content of BOX is empty."
(string-empty-p (plist-get box :content)))
(not (string-empty-p (plist-get box :content))))

(defvar grid-overline '(:overline t) "Overline face.")

Expand All @@ -71,7 +72,7 @@
(if (stringp width)
(floor
(* (window-width)
(/ (string-to-number width) 100.0)))
(/ (string-to-number width) 100.0)))
width))

(defun grid--reformat-content (content width align)
Expand All @@ -87,71 +88,82 @@

(defun grid--longest-line-length (string)
"Get the length of the longest line in STRING."
(let ((lines (split-string string "\n")))
(thread-last lines
(seq-map #'length)
(seq-max))))
(thread-last (split-string string "\n")
(seq-map #'length)
(seq-max)))

(defalias #'grid--merge-plists
(apply-partially #'map-merge-with 'plist (lambda (_ x) x))
"Merge plists, the last one takes precedence.")

(defun grid--fill-box (box)
"Calculate and fill in the missing fields in BOX."
;; `map-let' doesn't provide access to keywords directly
(map-let ((:content content)
(:align align)
(:padding padding)
(:width width))
box
(let* ((padding (* (or padding 0) 2))
(width-raw (or width (grid--longest-line-length content)))
(width (- (grid--normalize-width width-raw) padding))
(content (grid--reformat-content content width align))
(box-extra (list :width width
:content content
:length (length content))))
(when (< width 0)
(user-error "Horizonal padding %s must be less than width %s"
padding width-raw))
(grid--merge-plists box box-extra))))

(defun grid--normalize-box (box)
"Return a normalized copy of BOX."
(let* ((box (pcase box
((pred plistp) (copy-tree box))
((pred stringp) (list :content box))))
(content (plist-get box :content))
(align (plist-get box :align))
(padding (* (or (plist-get box :padding) 0) 2))
(width-raw
(or
(plist-get box :width)
(let ((width (grid--longest-line-length content)))
(setq box (plist-put box :width width))
width)))
(width (- (grid--normalize-width width-raw) padding)))
(when (< width 0)
(user-error "Horizonal padding must be less than width"))
(setq box (plist-put box :width width))
(setq box (plist-put box :content (grid--reformat-content content width align)))
(setq box (plist-put box :length (length (plist-get box :content))))
box))
"Normalize BOX to plist."
(cond
((plistp box) (copy-tree box))
((stringp box) (list :content box))))

(defun grid--format-box (box)
"Insert BOX in the current buffer."
(map-let ((:content content)
(:padding padding)
(:width width)
(:border border)
(:length length))
box
(let* ((content-len (length content))
(line-len (min width content-len))
(padding (make-string (or padding 0) ? ))
(fmt (format "%s%% -%ds%s" padding width padding))
(line (format fmt (substring content 0 line-len)))
(new-content (substring content
(min content-len (1+ width))))
(border-face (cond
;; first line?
((= length content-len) grid-overline)
;; in body?
((/= content-len 0) grid-vertical-borders)
;; last line?
((and (zerop content-len)
(string-empty-p new-content)) grid-underline))))
(when (and border border-face)
(grid--apply-face line border-face))
(setq box (plist-put box :content new-content))
line)))

(defun grid--insert-row (row)
"Insert ROW in the current buffer."
(while (not (seq-every-p #'grid-content-empty-p row))
(mapc #'grid--insert-box row)
(delete-char (* grid-margin -1))
(insert ?\n))
(let ((normalized-row (seq-map (lambda (box)
(grid--fill-box (grid--normalize-box box)))
row)))
(while (seq-some #'grid-content-not-empty-p normalized-row)
(mapc (lambda (box)
(insert (grid--format-box box))
(insert-char ? grid-margin))
normalized-row)
(delete-char (* grid-margin -1))
(insert ?\n)))
(insert ?\n))

(defun grid--insert-box (box)
"Insert BOX in the current buffer."
(let* ((content (plist-get box :content))
(content-len (length content))
(padding-len (or (plist-get box :padding) 0))
(padding (make-string padding-len ? ))
(width (plist-get box :width))
(line-len (min width content-len))
(line
(concat
padding
(format (format "%% -%ds" width)
(substring content 0 line-len))
padding))
(donep (string-empty-p content))
(new-content (substring content
(min content-len (1+ width)))))
(when (plist-get box :border)
(grid--apply-face line
(append
;; first line?
(and (= (plist-get box :length) content-len) grid-overline)
;; in body?
(and (/= content-len 0) grid-vertical-borders)
;; last line?
(and (not donep) (string-empty-p new-content) grid-underline))))
(insert line)
(insert-char ? grid-margin)
(setq box (plist-put box :content new-content))))

(defsubst grid--trim-line ()
(beginning-of-line)
(delete-horizontal-space)
Expand All @@ -178,21 +190,22 @@ ALIGN values: `left' (default), `right', `center', `full'."
(interactive "P")
(let (space)
(while (not (eobp))
(if align (grid--trim-line)
(end-of-line))
(if align
(grid--trim-line)
(end-of-line))
(setq space (- fill-column (current-column)))
(if (>= space 0)
(grid--align-line align space)
(let ((beg (line-beginning-position)))
(fill-region beg (line-end-position) align)
(goto-char beg)
(grid--trim-line)
(setq space (- fill-column (current-column)))
(when (< space 0)
(forward-char space)
(insert ?\n)
(setq space (+ fill-column space)))
(grid--align-line align space)))
(grid--align-line align space)
(let ((beg (line-beginning-position)))
(fill-region beg (line-end-position) align)
(goto-char beg)
(grid--trim-line)
(setq space (- fill-column (current-column)))
(when (< space 0)
(forward-char space)
(insert ?\n)
(setq space (+ fill-column space)))
(grid--align-line align space)))
(forward-line 1))))

;;; API
Expand All @@ -207,7 +220,7 @@ ALIGN values: `left' (default), `right', `center', `full'."

(defun grid-insert-row (row)
"Insert ROW in the current buffer."
(grid--insert-row (mapcar #'grid--normalize-box row)))
(grid--insert-row row))

(defun grid-insert-column (column)
"Insert COLUMN in the current buffer."
Expand Down