Created
December 15, 2023 10:45
-
-
Save chrisdone-artificial/de74990729a334717d467f8c7dfdacab to your computer and use it in GitHub Desktop.
albero.el
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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