Skip to content

Instantly share code, notes, and snippets.

@chrisdone-artificial
Created December 15, 2023 10:45
Show Gist options
  • Save chrisdone-artificial/de74990729a334717d467f8c7dfdacab to your computer and use it in GitHub Desktop.
Save chrisdone-artificial/de74990729a334717d467f8c7dfdacab to your computer and use it in GitHub Desktop.
albero.el
(defcustom albero-width 30
"Width of the albero window.")
(defvar albero-expanded (make-hash-table :test 'equal))
(defun albero-win-config-hook ()
(let ((w (albero-window)))
(when w
(albero-adjust-win w))))
(defun albero-adjust-win (w)
"Adjust the dimensions of the albero buffer."
(when (= (window-height w) (frame-height))
(set-window-parameter w 'no-other-window t)
(with-selected-window w
(enlarge-window-horizontally (- albero-width (window-width))))))
(defun albero-window ()
"Get the [singular] window of the albero buffer."
(let ((windows (remove-if-not (lambda (w) (eq (window-buffer w) (albero-buffer))) (window-list-1))))
(if (cadr windows)
nil ; Don't return the window if it's on the screen multiple times.
(car windows))))
(defun albero-buffer ()
(get-buffer-create "*albero*"))
(defun albero-set-root ()
"Set the root directory."
(interactive)
(let ((root (let ((path (car (string-split (shell-command-to-string "git rev-parse --show-toplevel") "\n"))))
(if (file-exists-p path)
path
default-directory))))
(with-current-buffer (albero-buffer)
(when (not (string= default-directory root))
(setq-local default-directory root)
(albero-refresh)))))
(defun albero-refresh ()
(interactive)
(with-current-buffer (albero-buffer)
(erase-buffer)
(insert (propertize (file-name-nondirectory default-directory) 'face 'dired-header) "\n\n")
(albero-insert default-directory "")))
(defun albero-insert (dir indentation)
(let* ((files (directory-files dir t "^[^.]"))
(annotated
(remove-if-not #'identity
(mapcar (lambda (file)
(let* ((dir (file-directory-p file))
(name (file-name-nondirectory file))
(display (if dir
(concat name "/")
name))
(icon (if dir "๐Ÿ“" "๐Ÿ“„")))
(unless (or (string= name ".") (string= name ".."))
(list :path file
:icon icon
:display display
:name name
:dir-p dir))))
files))))
(sort annotated
(lambda (x y)
(let ((x-dir (if (plist-get x :dir-p) 0 1))
(y-dir (if (plist-get y :dir-p) 0 1)))
(< x-dir y-dir))))
(dolist (file annotated)
(insert indentation
(plist-get file :icon)
" "
(if (plist-get file :dir-p)
(buttonize (plist-get file :display)
(if (gethash (plist-get file :path) albero-expanded)
'albero-collapse
'albero-expand)
(cons :indentation (cons indentation file)))
(plist-get file :display))
"\n")
(when (gethash (plist-get file :path) albero-expanded)
(albero-insert (plist-get file :path) (concat " " indentation))))))
(defun albero-expand (data)
(interactive)
(let ((button (button-at (point))))
(button-put button 'action 'albero-collapse)
(save-excursion
(goto-char (1+ (line-end-position)))
(puthash (plist-get data :path) t albero-expanded)
(albero-insert (plist-get data :path) (concat " " (plist-get data :indentation))))))
(defun albero-collapse (data)
(interactive)
(let ((button (button-at (point))))
(button-put button 'action 'albero-expand)
(save-excursion
(remhash (plist-get data :path) albero-expanded)
(albero-refresh))))
(add-hook 'window-configuration-change-hook 'albero-win-config-hook)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment