;;; my-help.el -- Help related extensions for emacs core -*- 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: ;; Emacs help related extensions. ;;; Code: ;; find source of external command (defun my-external-command-open-source (command) (interactive (list (completing-read "Open source of command: " (my-external-command-collection)))) (let ((subject (cadr (split-string (my-shell-command-output (format "type %s" command)) " is ")))) (pcase subject ("a shell builtin" (error "%s is %s" command subject)) ("a shell keyword" (error "%s is %s" command subject)) ((guard (string-prefix-p "is aliased to " subject)) (substring subject (error "%s is %s" command subject))) (_ (pcase-let ((`(,path ,type) (split-string (my-shell-command-output (format "file -Li %s" subject)) ": "))) (if (string-prefix-p "text/" type) (progn (message "Opening %s" path) (find-file path)) (error "%s (%s) is not plaintext: %s" command path type))))))) (defun my-external-command-collection () (mapcan (lambda (dir) (mapcar (lambda (file) (string-match "\\(?:.*\\)/\\(.*\\)" file) (match-string 1 file)) (seq-filter (lambda (file) (and (not (file-directory-p file)) (file-executable-p file))) (directory-files dir t "[^~#]$")))) (seq-filter 'file-accessible-directory-p (exec-path)))) (defun my-woman-man (arg) (interactive "P") (if arg (call-interactively 'man) (call-interactively 'woman))) (defun my-help-goto-symbol (symbol) (interactive ;; copied from prompt code of help-describe-symbol (let* ((v-or-f (symbol-at-point)) (found (if v-or-f (cl-some (lambda (x) (funcall (nth 1 x) v-or-f)) describe-symbol-backends))) (v-or-f (if found v-or-f (function-called-at-point))) (found (or found v-or-f)) (enable-recursive-minibuffers t) (val (completing-read (format-prompt "Describe symbol" (and found v-or-f)) #'help--symbol-completion-table (lambda (vv) (cl-some (lambda (x) (funcall (nth 1 x) vv)) describe-symbol-backends)) t nil nil (if found (symbol-name v-or-f))))) (list (if (equal val "") (or v-or-f "") (intern val))))) (help-do-xref nil #'describe-symbol (list symbol))) (defun my-describe-local-variable (variable &optional buffer frame) (interactive (let ((v (variable-at-point)) (enable-recursive-minibuffers t) (orig-buffer (current-buffer)) val) (setq val (completing-read (format-prompt "Describe variable" (and (symbolp v) v)) #'help--symbol-completion-table (lambda (vv) (and (local-variable-p vv) (or (get vv 'variable-documentation) (and (not (keywordp vv)) ;; Since the variable may only exist in the ;; original buffer, we have to look for it ;; there. (buffer-local-boundp vv orig-buffer))))) t nil nil (if (symbolp v) (symbol-name v)))) (list (if (equal val "") v (intern val))))) (describe-variable variable buffer frame)) (defun my-info-display-manual () (interactive) (call-interactively 'info-display-manual) (when (derived-mode-p 'Info-mode) (rename-buffer (generate-new-buffer-name (format "*info %s*" (file-name-sans-extension (file-name-nondirectory Info-current-file))))))) (defun my-describe-symbol-at-point () (interactive) (describe-symbol (symbol-at-point))) (provide 'my-help) ;;; my-help.el ends here