emacs-btap.el (5096B)
1 ;;; -*- lexical-binding: t -*- 2 ;;; 3 ;;; emacs-btap.el 4 ;;; 5 ;;; Browse thing at point. 6 ;;; 7 ;;; Copyright (C) 2020 Tomas Hlavaty <tom at logand dot com> 8 ;;; 9 ;;; License: GPLv3 or later 10 ;;; 11 ;;; Download: git clone https://logand.com/git/emacs-btap.git 12 ;;; 13 ;;; Example configuration: 14 ;;; 15 ;;; (add-to-list 'load-path "~/git/emacs-btap") 16 ;;; (require 'emacs-btap) 17 ;;; (global-set-key "\M-f" 'btap) 18 ;;; 19 ;;; Example usage: 20 ;;; 21 ;;; M-x btap will browse the thing at point. 22 ;;; 23 ;;; Some variables can be customized in the btap group. 24 ;;; 25 ;;; To see a few examples, evaluate: (occur "example:") 26 27 (require 'browse-url) 28 (require 'cl-lib) 29 (require 'ffap) 30 (require 'thingatpt) 31 32 (defcustom btap-try-functions '( 33 ;; global 34 btap-try-notmuch 35 btap-try-man 36 btap-try-url 37 btap-try-file 38 btap-try-wild-file 39 btap-try-clhs 40 btap-try-sbcl-bug 41 ;; mode specific 42 btap-try-cc-mode 43 btap-try-lisp-mode 44 ;; nothing matched 45 btap-try-missing 46 ) 47 "List of functions to try to handle btap action. 48 Functions accept optional string argument and should return nil if not 49 applicable for the given string. If no string is given, the function 50 should guess from the thing at point. The first applicable function 51 handles the btap action." 52 :type '(repeat symbol) 53 :group 'btap) 54 55 (defvar btap--ffap-guesser-thunk) 56 (defun btap-ffap-guesser () 57 (funcall btap--ffap-guesser-thunk)) 58 59 (defun btap-try-notmuch (&optional string) 60 (when (fboundp 'notmuch-show) 61 (let ((x (or string (btap-ffap-guesser)))) 62 (when (and x (string-match "^id:" x)) 63 (funcall 'notmuch-show x) 64 x)))) 65 66 (defun btap-try-man (&optional string) 67 (when browse-url-man-function 68 (let ((x (or string (btap-ffap-guesser)))) 69 (when (and x (string-match "^man:" x)) 70 (funcall browse-url-man-function x) 71 x)))) 72 ;; example: man:printf 73 74 (defun btap-try-url (&optional string) 75 (when ffap-url-fetcher 76 (let ((x (or string (btap-ffap-guesser)))) 77 (when x 78 (let ((url (ffap-url-p x))) 79 (when url 80 (let (current-prefix-arg) 81 (funcall ffap-url-fetcher url) 82 url))))))) 83 ;; example: https://logand.com 84 85 (defun btap-try-cc-mode (&optional string) 86 (when (and (boundp 'c-buffer-is-cc-mode) 87 c-buffer-is-cc-mode) 88 (let ((x (or string (thing-at-point 'word t)))) 89 (when x 90 ;; TODO includes e.g. limits.h 91 (btap-try-man (concat "man:" x)))))) 92 93 (defun btap-try-file (&optional string) 94 (when ffap-file-finder 95 (let ((x (or string (btap-ffap-guesser)))) 96 (when x 97 (let ((url (ffap-url-p x))) 98 (unless url 99 (when (file-exists-p x) 100 (funcall ffap-file-finder (expand-file-name x)) 101 x))))))) 102 ;; example: ~/.emacs 103 ;; example: ~/.emacs.d 104 105 (defun btap-try-wild-file (&optional string) 106 (when (and ffap-dired-wildcards 107 find-file-wildcards 108 ffap-file-finder) 109 (let ((x (or string (btap-ffap-guesser)))) 110 (when x 111 (let ((url (ffap-url-p x))) 112 (unless url 113 (when (and (string-match ffap-dired-wildcards x) 114 ;; Check if it's find-file that supports wildcards arg 115 (memq ffap-file-finder '(find-file find-alternate-file))) 116 (funcall ffap-file-finder (expand-file-name x) t) 117 x))))))) 118 119 (defun btap-try-clhs (&optional string) 120 (when (fboundp 'hyperspec-lookup) 121 (let ((x (or string (btap-ffap-guesser)))) 122 (when (and x (string-match "^clhs:" x)) 123 (funcall 'hyperspec-lookup (substring x 5)) 124 x)))) 125 ;; example: clhs:delete-if 126 127 (defun btap-try-lisp-mode (&optional string) 128 (when (and (fboundp 'hyperspec-lookup) 129 (eq major-mode 'lisp-mode)) 130 (let ((x (or string (thing-at-point 'word t)))) ;; TODO include - etc 131 (when x 132 (funcall 'hyperspec-lookup x) 133 x)))) 134 135 (defun btap-try-sbcl-bug (&optional string) 136 (let ((x (or string (thing-at-point 'filename t)))) 137 (when (and x (string-match "^lp#" x)) 138 (btap-try-url (concat "https://bugs.launchpad.net/bugs/" (substring x 3)))))) 139 ;; example: lp#1903901 140 141 (defun btap-try-missing () 142 (signal 'btap-try-missing (list "Nothing at point to browse"))) 143 ;; example: /does-not-exist 144 145 (defun btap--memoize-thunk (thunk) 146 (let (z) 147 (lambda () 148 (when thunk 149 (setq z (funcall thunk) 150 thunk nil)) 151 z))) 152 153 (defun btap () 154 "Browse thing at point. See also the variable `btap-try-functions'." 155 (interactive) 156 (let (z 157 (btap--ffap-guesser-thunk (btap--memoize-thunk 'ffap-guesser)) 158 (x btap-try-functions)) 159 (while (and x (not (setq z (funcall (pop x)))))) 160 z)) 161 162 (provide 'emacs-btap)