Skip to content

Instantly share code, notes, and snippets.

@rougier
Created November 21, 2022 19:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rougier/3657a24f25d6d64550281c32a39cde8d to your computer and use it in GitHub Desktop.
Save rougier/3657a24f25d6d64550281c32a39cde8d to your computer and use it in GitHub Desktop.
An emacs folding box function
(defun folding-box (content &optional size title prefix type folded)
"Enclose TEXT with a box of given SIZE with an optional TITLE at
the top.
If a PREFIX is given, it is prepended to the box such that total
size is enforced, including prefix. If a title is given, the
content of the box can be shown/hidden by clicking on the title
and initial state is specified with FOLDED. The type of the box
can be either 'unicode or 'ascii."
(let* ((prefix (or prefix ""))
(size (or size -1))
(size (cond ((and size (> size 0)) size)
((and size (< size 0)) (+ (window-width) size))
(t (- (window-size) 1))))
(type (or type 'unicode))
(content (with-temp-buffer
(insert content)
(goto-char (point-min))
;; 6 instead of 4 to have room for the "filler"
(let ((fill-column (- size 6))
(sentence-end-double-space nil))
(fill-region (point-min) (point-max)))
(buffer-substring (point-min) (point-max))))
(fill-title (propertize " "
'display `(space :align-to ,(- size 2))))
(fill-body (propertize " "
'display `(space :align-to ,(- size 2))))
(keymap (let ((map (make-sparse-keymap)))
(define-key map [mouse-2] #'folding-box--toggle)
(define-key map (kbd "TAB") #'folding-box--toggle)
(define-key map (kbd "RET") #'folding-box--toggle)
map))
(body-format (concat prefix "│ "
(propertize "%s" 'face 'default)
fill-body
" │\n"))
(header (concat prefix
"┌"
(make-string (- size (length prefix) 2) ?─)
"┐\n"))
(footer (concat prefix
"└"
(make-string (- size (length prefix) 2) ?─)
"┘"))
(body (mapconcat (lambda (line)
(format body-format line))
(split-string content "[\n]") ""))
(title (when title (truncate-string-to-width title
(- size (length prefix) 4) nil nil "…")))
(title (when title (concat prefix "│ "
(propertize (concat title fill-title)
'face 'nano-strong
'mouse-face 'highlight
'body-size (length body)
'follow-link t
'help-echo "Click to fold/unfold box content"
'keymap keymap)
" │\n")))
(body (propertize body 'invisible folded)))
(concat header
(when title title)
body footer)))
(defun folding-box--toggle ()
(interactive)
(let ((body-size (get-text-property (point) 'body-size)))
(when body-size
(save-excursion
(end-of-line)
(let ((invisible (not (get-text-property (+ (point) 1) 'invisible))))
(add-text-properties (+ (point) 1) (+ (point) body-size 1)
`(invisible ,invisible)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment