diff --git a/.emacs.d/lisp/package-cl-inspect-mode.el b/.emacs.d/lisp/package-cl-inspect-mode.el index 7fedeaa5..382c4d9c 100644 --- a/.emacs.d/lisp/package-cl-inspect-mode.el +++ b/.emacs.d/lisp/package-cl-inspect-mode.el @@ -35,12 +35,79 @@ If ENTRY element at INDEX is a number, sort by number, otherwise sort by string. (clinspect--tabulated-list-sorter (car entries) index)))) (number-sequence 0 (1- (length header)))))) +(defun clinspect--vector->list (vector) + (cl-loop for i from 0 below (length vector) + collect (aref vector i))) + +(defun clinspect--test-filter (entry) + (let ((path (aref (cadr entry) 0))) + (string-match-p "agenda" path))) + +(defvar clinspect-filters (list #'identity)) +(setq clinspect-filters (list #'clinspect--test-filter)) + +(defun clinspect--filter-column (index predicate) + (lambda (entry) + (let ((value (aref (cadr entry) index))) + (funcall predicate value)))) + +(defun clinspect--number-filter (index) + (let ((min (read-from-minibuffer "Min value (empty means none): " nil nil :read nil "nil")) + (max (read-from-minibuffer "Max value (empty means none): " nil nil :read nil "nil")) + (number (string-to-number value))) + (clinspect--filter-column + index + (lambda (value) + (cond + ((and min max) + (<= min number max)) + (min + (<= min number )) + (max + (<= number max))))))) + +(defun clinspect-add-filter () + (interactive) + (let* ((column-names (mapcar #'car (clinspect--vector->list tabulated-list-format))) + (column (completing-read "Column to filter by: " column-names)) + (index (cl-position column column-names :test #'equal)) + (sample (aref (cadr (car clinspect--tabulated-list-entries)) index)) + (revert? t)) + (cl-typecase (car (read-from-string sample)) + (integer + (add-to-list 'clinspect-filters (clinspect--number-filter index))) + (t (message "Unsupported column values to infer filter.") + (setq revert? nil))) + + (when revert? + (tabulated-list-revert)))) + +(defun clinspect-reset-filters () + (interactive) + (setq clinspect-filters (list #'identity)) + (tabulated-list-revert)) + +(defun clinspect--refresh () + ;; TODO: Use -orfn / -andfn? + (setq tabulated-list-entries + (cl-loop for entry in clinspect--tabulated-list-entries + when (cl-loop for filter in clinspect-filters + always (funcall filter entry)) + collect entry) + ;; (clinspect-filter + ;; clinspect--tabulated-list-entries) + ) + (tabulated-list-init-header)) + (define-derived-mode clinspect-mode tabulated-list-mode "Clinspect" "Mode to inspect Common Lisp sequences." - (add-hook 'tabulated-list-revert-hook 'tabulated-list-init-header nil t)) + (add-hook 'tabulated-list-revert-hook 'clinspect--refresh nil t)) (defvar clinspect-buffer-name "clinspector") +(defvar-local clinspect--tabulated-list-entries nil + "Backup of `tabulated-list-entries', in case the latter gets filtered.") + (defun clinspect (header data &optional name) "Inspect DATA. DATA is a list of things. @@ -51,7 +118,7 @@ HEADER is a list of strings, the column names." (format "<%s>" name) "")))) (clinspect-mode) - (setq tabulated-list-entries + (setq clinspect--tabulated-list-entries (cl-loop for line in data for index from 1 upto (length header) collect (list index (apply #'vector (mapcar #'prin1-to-string line)))))