Subject: bug#26712: other-window/frame versions of find-library

From: "Charles A. Roelli" <[email-masked]>
Date: Mon, 29 May 2017 21:39:10 +0200

Good idea.  Is the attached patch OK?  It augments 'C-x F', 'C-x 4 F'
and 'C-x 5 F' to suggest library names too.

On 21/05/2017 05:23, Richard Stallman wrote:
> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]
>
> I think find-function is more useful to put on a key than
> find-library.  Or perhaps they can be combined.  It should not be hard
> to accept an argument and try it first as a function, then as a library.
>
> If the name is both a function and a library, the function definition
> is almost surely in that library.
>
>From 0c309fb5ad41d4c8c7e356ef365a02b6550a0e2e Mon Sep 17 00:00:00 2001
From: Charles A. Roelli <[email-masked]>
Date: Mon, 29 May 2017 21:35:24 +0200
Subject: [PATCH] New commands: find-function-or-library
 (-other-window/-frame)

* lisp/emacs-lisp/find-func.el (read-function-or-library-name):
New function for reading a function or library name.
(find-function-or-library, find-function-or-library-other-window)
(find-function-or-library-other-frame): New commands.
(find-function-setup-keys): Replace 'find-function' bindings with
bindings to 'find-function-or-library'.
* etc/NEWS: Mention 'find-function-or-library' and new bindings
made by 'find-function-setup-keys'.
---
 etc/NEWS                     |    6 +++
 lisp/emacs-lisp/find-func.el |   90 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 93 insertions(+), 3 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 60066b7..ee6efb9 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -363,6 +363,12 @@ large integers from being displayed as characters.
 ** Two new commands for finding the source code of Emacs Lisp
 libraries: 'find-library-other-window' and 'find-library-other-frame'.
 
+** 'find-function-setup-keys' now binds 'C-x F', 'C-x 4 F' and 'C-x 5
+F' to the new command 'find-function-or-library' and its
+other-window/-frame counterparts.  The new commands find the Emacs
+Lisp source code of a function or library, defaulting to the function
+or library closest to point.
+
 
 * Editing Changes in Emacs 26.1
 
diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el
index 9b98f05..9943598 100644
--- a/lisp/emacs-lisp/find-func.el
+++ b/lisp/emacs-lisp/find-func.el
@@ -310,6 +310,40 @@ read-library-name
                        "Library name: ")
                      table nil nil nil nil def)))
 
+(defun read-function-or-library-name ()
+  "Read and return a function or library name, defaulting to the one near point.
+
+A function name is the name of a symbol that satisfies the
+predicate `fboundp'.  A library name is the filename of an Emacs
+Lisp library located in a directory under `load-path' (or
+`find-function-source-path', if non-nil)."
+  (let* ((dirs (or find-function-source-path load-path))
+         (suffixes (find-library-suffixes))
+         (table (completion-table-merge
+                 (apply-partially 'completion-table-with-predicate
+                                  obarray 'fboundp t)
+                 (apply-partially 'locate-file-completion-table
+                                  dirs suffixes)))
+         (def (if (eq (function-called-at-point) 'require)
+                  ;; `function-called-at-point' may return 'require
+                  ;; with `point' anywhere on this line.  So wrap the
+                  ;; `save-excursion' below in a `condition-case' to
+                  ;; avoid reporting a scan-error here.
+                  (condition-case nil
+                      (save-excursion
+                        (backward-up-list)
+                        (forward-char)
+                        (forward-sexp 2)
+                        (thing-at-point 'symbol))
+                    (error nil))
+                (symbol-name (function-called-at-point)))))
+    (when (and def (not (test-completion def table)))
+      (setq def nil))
+    (completing-read (if def
+                         (format "Function or library name (default %s): " def)
+                       "Function or library name: ")
+                     table nil nil nil nil def)))
+
 ;;;###autoload
 (defun find-library-other-window (library)
   "Find the Emacs Lisp source of LIBRARY in another window.
@@ -537,6 +571,56 @@ find-function-other-frame
   (find-function-do-it function nil 'switch-to-buffer-other-frame))
 
 ;;;###autoload
+(defun find-function-or-library (function-or-library)
+  "Find the definition of the FUNCTION-OR-LIBRARY near point.
+
+Finds the source file containing the definition of the
+function (selected by `function-called-at-point') or
+library (loaded with `require') near point in a buffer and places
+point before the definition.
+
+FUNCTION-OR-LIBRARY is searched for in
+`find-function-source-path', if non-nil, otherwise in
+`load-path'.  See also `find-function-recenter-line' and
+`find-function-after-hook'.
+
+If FUNCTION-OR-LIBRARY names both a function and a library, finds
+the corresponding function definition."
+  (interactive (list (read-function-or-library-name)))
+  (let ((sym (if (stringp function-or-library)
+                 (intern function-or-library)
+               function-or-library)))
+    (if (fboundp sym)
+        (find-function-do-it sym nil 'switch-to-buffer)
+      (find-library function-or-library))))
+
+;;;###autoload
+(defun find-function-or-library-other-window (function-or-library)
+  "Find, in another window, the definition of FUNCTION-OR-LIBRARY near point.
+
+See `find-function' for more details."
+  (interactive (list (read-function-or-library-name)))
+  (let ((sym (if (stringp function-or-library)
+                 (intern function-or-library)
+               function-or-library)))
+    (if (fboundp sym)
+        (find-function-do-it sym nil 'switch-to-buffer-other-window)
+      (find-library-other-window function-or-library))))
+
+;;;###autoload
+(defun find-function-or-library-other-frame (function-or-library)
+  "Find, in another frame, the definition of FUNCTION-OR-LIBRARY near point.
+
+See `find-function' for more details."
+  (interactive (list (read-function-or-library-name)))
+  (let ((sym (if (stringp function-or-library)
+                 (intern function-or-library)
+               function-or-library)))
+    (if (fboundp sym)
+        (find-function-do-it sym nil 'switch-to-buffer-other-frame)
+      (find-library-other-frame function-or-library))))
+
+;;;###autoload
 (defun find-variable-noselect (variable &optional file)
   "Return a pair `(BUFFER . POINT)' pointing to the definition of VARIABLE.
 
@@ -691,9 +775,9 @@ find-variable-at-point
 ;;;###autoload
 (defun find-function-setup-keys ()
   "Define some key bindings for the find-function family of functions."
-  (define-key ctl-x-map "F" 'find-function)
-  (define-key ctl-x-4-map "F" 'find-function-other-window)
-  (define-key ctl-x-5-map "F" 'find-function-other-frame)
+  (define-key ctl-x-map "F" 'find-function-or-library)
+  (define-key ctl-x-4-map "F" 'find-function-or-library-other-window)
+  (define-key ctl-x-5-map "F" 'find-function-or-library-other-frame)
   (define-key ctl-x-map "K" 'find-function-on-key)
   (define-key ctl-x-4-map "K" 'find-function-on-key-other-window)
   (define-key ctl-x-5-map "K" 'find-function-on-key-other-frame)
-- 
1.7.4.4