Heime <[email protected]> writes:
> I've struggled to list interactive functions from .el files using obarray
> symbols, as it requires prior loading. I need to parse unloaded .el files
> directly to extract defun forms with (interactive ...).
>
> Current broken code:
>
> (defun ramazones-smbptn (smb pattern file)
> "Filter symbol SMB defined in a specific file that are currently loaded."
> (when (and (commandp smb)
> (string-match-p pattern (symbol-name smb)))
> smb))
>
> (defun ramazonas-agfun (file pattern)
> "List all interactive functions defined in FILE."
>
> (interactive
> (list
> (read-file-name "File: ")
> (read-regexp "Symbol Pattern (RET for all): ")))
>
> (let ( (smbs nil)
> (count 0) )
> (when (find-file-noselect file)
> (mapatoms (lambda (smb)
> (when (ramazonas-smbptn smb pattern file)
> (setq count (1+ count))
> (push smb smbs))))
>
> (if (> count 0)
> (progn (message "Interactive functions: %s"
> (seq-filter #'commandp smbs))
> (seq-filter #'commandp smbs))
> (message "No interactive functions found")))))
>
1. You should be able to look up the symbols of files that
Emacs has loaded, as the ‘let’ expressions demonstrated.
But, as you point out, it does not work for Emacs Lisp
files whose code has not yet been loaded.
2. The code does not check the values of ‘file’, whether it
is provided interactively or non-interactively. It
should be changed to do that.
(when (find-file-noselect file) ...)
returns nil when ‘file’ has a value that is does not
correctly specify an existing, readable file. Before
this expression is evaluated, the value assigned to ‘file’
should be checked. For example,
(if (file-exists-p file)
;; then code
;; else
(error "No such file %s" file))
or
(if (file-readable-p file)
;; then code
;; else
(error "Cannot read file %s" file))
See:
(info "(elisp) Testing Accessibility")
3. The function ‘find-file-noselect’ reads the text of a
file into an Emacs buffer, but this is not what your
function needs. Instead, it needs to "load" the Emacs
Lisp code in the file, that is, it reads the Emacs Lisp
expressions in the file and evaluates them.
(info "(emacs) Lisp Libraries")
(info "(elisp) How Programs Do Loading")
4. When ‘file’ is specified using "~/...", then the
expression (string= (symbol-file smb) file) will
return nil because (symbol-file smb) returns the full
pathname to the file. In order to prevent this, ‘file’
should be expanded to the full pathname using ‘expand-file-name’
C-h f symbol-file
"The value is normally an absolute file name. It can also be nil,
if the definition is not associated with any file. If SYMBOL
specifies an autoloaded function, the value can be a relative
file name without extension."
So, for autoloaded functions, the code can still fail.
5. The expression (seq-filter #'commandp smbs) is not needed
because the symbols have already been filtered to create a
list of commands, that is, (seq-filter #'commandp smbs) =
smbs.
6. Likewise, ‘count’ is not needed (it was added to help
with debugging). (if (> count 0) ...) can be replaced
with (if smbs ...)
7. The helper function ‘ramazonas-smbptn’ is called many
times, passing ‘pattern’ and ‘file’, which do not change.
Replace
(when (ramazonas-smbptn smb pattern file)
(setq count (1+ count))
(push smb smbs))
with
(when (and (commandp smb)
(string-match-p pattern (symbol-name smb))
(string= (symbol-file smb) full-name))
(push smb smbs))
and delete the definition of ‘ramazonas-smbptn’.
Edited version with the suggested changes, above:
(defun mazonas-agfun (file pattern)
"List all commands defined in FILE whose names match PATTERN."
(interactive
(list
(read-file-name "File: ")
(read-regexp "Symbol Pattern (RET for all): ")))
(if (file-readable-p file)
(let ((smbs nil)
(full-name (expand-file-name file)))
(load-file full-name)
(mapatoms (lambda (smb)
(when (and (commandp smb)
(string-match-p pattern (symbol-name smb))
(string= (symbol-file smb) full-name))
(push smb smbs))))
(when smbs
(message "%S" smbs))
smbs)
(error "Cannot read file %s" file)))
With these changes, ‘mazonas-agfun’ has three possible
results:
1. Return a list of loaded symbols for ‘file’ that match ‘pattern’
2. nil, when there are no matches
3. Error, if the file does not exist or is unreadable.
It can also have a run-time error if there are errors in the
Emacs Lisp expressions in ‘file’ that cause ‘load-file’ to fail.
--
The lyf so short, the craft so long to lerne.
- Geoffrey Chaucer, The Parliament of Birds.
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.