;;; generic-search.el -- A search result UI -*- lexical-binding: t -*- ;; Copyright (C) 2023 Free Software Foundation. ;; Author: Yuchen Pei ;; Package-Requires: ((emacs "28.2")) ;; This file is part of dotfiles. ;; dotfiles is free software: you can redistribute it and/or modify it ;; under the terms of the GNU Affero General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; dotfiles is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; Affero General Public License for more details. ;; You should have received a copy of the GNU Affero General Public ;; License along with dotfiles. If not, see ;; . ;;; Commentary: ;; A search result UI. A generic search result mode displaying a list ;; of things, and action on an item ;;; Code: (defvar-local generic-search-transformer nil) (defvar-local generic-search-formatter nil) (defvar-local generic-search-default-action nil) (defvar-local generic-search-results nil) (defvar-local generic-search-keymap nil) (defvar generic-search-default-transformer 'identity) (defvar generic-search-default-formatter 'pp) (defvar generic-search-default-default-action 'generic-search-message-pp) (defvar generic-search-default-keymap button-map) (defun generic-search-message-pp (data) (interactive) (message (pp data))) (define-derived-mode generic-search-mode special-mode "Generic search" "Search results.") (defun generic-search-buffer-name (name) (format "*generic-search %s*" name)) (defun generic-search-open (results name &optional display-options) (let ((buffer-name (generic-search-buffer-name name))) (with-current-buffer (get-buffer-create buffer-name) (generic-search-mode) (setq generic-search-results results generic-search-formatter (or (alist-get 'formatter display-options) generic-search-default-formatter) generic-search-default-action (or (alist-get 'default-action display-options) generic-search-default-default-action) generic-search-keymap (or (alist-get 'keymap display-options) generic-search-default-keymap) generic-search-transformer (or (alist-get 'transfomer display-options generic-search-default-transformer))) (generic-search-update) (switch-to-buffer-other-window buffer-name)))) (defun generic-search-update () (let ((inhibit-read-only t)) (erase-buffer) (insert (format "%s Results:" (length generic-search-results))) (seq-do (lambda (result) (insert "\n----\n") (let ((start (point))) (insert (funcall generic-search-formatter result)) (make-text-button start (point) 'action generic-search-default-action 'button-data (funcall generic-search-transformer result) 'keymap generic-search-keymap))) generic-search-results) (goto-char (point-min)) (forward-button 1))) (defun generic-search-refresh () (interactive) (generic-search-update)) (define-key generic-search-mode-map "\t" 'forward-button) (define-key generic-search-mode-map [backtab] 'backward-button) (define-key generic-search-mode-map "g" 'generic-search-refresh) (provide 'generic-search)