Detect more package suggestions

* admin/scrape-elpa.el (scrape-elpa--safe-eval): Add new
function.
(scrape-elpa): Evaluate part of the matched expression to catch
more entries.
* etc/package-autosuggest.eld: Update database.
This commit is contained in:
Philip Kaludercic 2026-02-09 19:22:07 +01:00
parent 1aabe135e6
commit 4a3640c3f8
No known key found for this signature in database
2 changed files with 70 additions and 4 deletions

View file

@ -1,6 +1,6 @@
;;; scrape-elpa.el --- Collect ELPA package suggestions -*- lexical-binding: t; -*-
;; Copyright (C) 2024 Free Software Foundation, Inc.
;; Copyright (C) 2024, 2026 Free Software Foundation, Inc.
;; Author: Philip Kaludercic <philipk@posteo.net>
;; Keywords: tools
@ -25,6 +25,39 @@
;;; Code:
(require 'rx)
(defun scrape-elpa--safe-eval (exp &optional vars)
"Manually evaluate EXP without potentially dangerous side-effects.
The optional argument VARS may be an alist mapping symbols to values,
used when evaluating variables. The evaluation function is not meant to
be comprehensive, but just to handle the kinds of expressions that
`scrape-elpa' expects to encounter."
(pcase-exhaustive exp
;; special handling for macros
(`(rx . ,body) (rx-to-string `(: . ,body) t))
;; quoting and quasi-quoting
(`',x x)
(`(purecopy ,x) x)
((and (guard (eq '\` (car-safe exp))) (let `(,car . ,cdr) (cadr exp)))
(cons
(if (eq (car-safe car) '\,) (scrape-elpa--safe-eval (cadr car) vars) car)
(if (eq (car-safe cdr) '\,) (scrape-elpa--safe-eval (cadr cdr) vars) cdr)))
;; supported functions
(`(cons ,car ,cdr)
(cons (scrape-elpa--safe-eval car vars)
(scrape-elpa--safe-eval cdr vars)))
(`(concat . ,args)
(apply #'concat (mapcar #'scrape-elpa--safe-eval args)))
;; self-evaluating forms
((pred macroexp-const-p) exp)
;; variable evaluation
((pred symbolp)
(let ((ent (assq exp vars)))
(if ent (cdr ent) (signal 'void-variable exp))))))
(scrape-elpa--safe-eval '(cons "\\.go\\'" 'go-mode))
(defun scrape-elpa (&rest directories)
"Scrape autoload files in DIRECTORIES for package suggestions.
This file will automatically update \"package-autosuggest.eld\", but not
@ -57,6 +90,7 @@ Please review the results before updating the autosuggest database!"
"Scraping files..."
(and-let* (((string-match "/\\([^/]+?\\)-autoloads\\.el\\'" file))
(pkg (intern (match-string 1 file)))
(vars (list '(#:nihil)))
(inhibit-message t))
(with-temp-buffer
(insert-file-contents file)
@ -64,16 +98,34 @@ Please review the results before updating the autosuggest database!"
(while t
(dolist (exp (macroexp-unprogn (read (current-buffer))))
(pcase exp
(`(defconst ,(and (pred symbolp) var) ,val . ,_)
(catch 'ignore
(push
(cons var (condition-case err
(scrape-elpa--safe-eval val vars)
(t (message "Failed to evaluate %S: %S in %S" exp err vars)
(throw 'ignore nil))))
vars)))
(`(add-to-list
',(and (or 'interpreter-mode-alist
'magic-mode-alist
'auto-mode-alist)
variable)
'(,(and (pred stringp) regexp) .
,(and (pred symbolp) mode)))
,(let `(,(and (pred stringp) regexp) .
,(and (pred symbolp) mode))
(condition-case err
(scrape-elpa--safe-eval _ vars)
(t (message "Failed to evaluate %S: %S in %S" exp err vars)
nil))))
(terpri)
(prin1 (append (list pkg variable regexp)
(and (not (eq pkg mode)) (list mode))))))))
(and (not (eq pkg mode)) (list mode)))))
(`(add-to-list
',(or 'interpreter-mode-alist
'magic-mode-alist
'auto-mode-alist)
_)
(_ (message "Skipped over %S" exp))))))
(end-of-file nil))))))
(insert "\n)\n")))

View file

@ -41,6 +41,7 @@
(gle-mode auto-mode-alist "\\.gle\\'")
(gpr-mode auto-mode-alist "\\.gpr\\'")
(html5-schema auto-mode-alist "\\.html?\\'" nxml-mode)
(idlwave auto-mode-alist "\\.pro\\'" idlwave-mode)
(jgraph-mode auto-mode-alist "\\.jgr\\'")
(json-mode auto-mode-alist "\\.json\\'")
(lmc auto-mode-alist "\\.elmc\\'" lmc-asm-mode)
@ -55,6 +56,7 @@
(omn-mode auto-mode-alist "\\.omn\\'")
(poke-mode auto-mode-alist "\\.pk\\'")
(pspp-mode auto-mode-alist "\\.sps\\'")
(python auto-mode-alist "\\(?:\\.\\(?:p\\(?:th\\|y[iw]?\\)\\)\\|/\\(?:SCons\\(?:\\(?:crip\\|truc\\)t\\)\\)\\)\\'" python-mode)
(python interpreter-mode-alist "python[0-9.]*" python-mode)
(python auto-mode-alist "/\\(?:Pipfile\\|\\.?flake8\\)\\'" conf-mode)
(rec-mode auto-mode-alist "\\.rec\\'")
@ -62,8 +64,10 @@
(sed-mode auto-mode-alist "\\.sed\\'")
(sed-mode interpreter-mode-alist "sed")
(shen-mode auto-mode-alist "\\.shen\\'")
(show-font auto-mode-alist "\\.\\(ttf\\|otf\\)\\'" show-font-mode)
(sisu-mode auto-mode-alist "\\.ss[imt]\\'")
(smalltalk-mode auto-mode-alist "\\.st\\'")
(smalltalk-mode auto-mode-alist "\\.star\\'" archive-mode)
(sml-mode auto-mode-alist "\\.s\\(ml\\|ig\\)\\'")
(sml-mode auto-mode-alist "\\.cm\\'" sml-cm-mode)
(sml-mode auto-mode-alist "\\.grm\\'" sml-yacc-mode)
@ -77,6 +81,7 @@
(systemd auto-mode-alist "\\.swap\\'" systemd-swap-mode)
(systemd auto-mode-alist "\\.timer\\'" systemd-timer-mode)
(vcard auto-mode-alist "\\.[Vv][Cc][Ff]\\'" vcard-mode)
(vcl-mode auto-mode-alist "\\.vcl\\'")
(wisi auto-mode-alist "\\.parse_table.*\\'" wisitoken-parse_table-mode)
(wisitoken-grammar-mode auto-mode-alist "\\.wy\\'" simple-indent-mode)
(wisitoken-grammar-mode auto-mode-alist "\\.wy\\'")
@ -107,6 +112,7 @@
(coffee-mode interpreter-mode-alist "coffee")
(d-mode auto-mode-alist "\\.d[i]?\\'")
(dart-mode auto-mode-alist "\\.dart\\'")
(dockerfile-mode auto-mode-alist "[/\\]\\(?:Containerfile\\|Dockerfile\\)\\(?:\\.[^/\\]*\\)?\\'")
(dockerfile-mode auto-mode-alist "\\.dockerfile\\'")
(drupal-mode auto-mode-alist "[^/]\\.\\(module\\|test\\|install\\|profile\\|tpl\\.php\\|theme\\|inc\\)\\'" php-mode)
(drupal-mode auto-mode-alist "[^/]\\.info\\'" conf-windows-mode)
@ -121,6 +127,7 @@
(geiser-racket auto-mode-alist "\\.rkt\\'" scheme-mode)
(gnu-apl-mode auto-mode-alist "\\.apl\\'")
(gnu-apl-mode interpreter-mode-alist "apl")
(go-mode auto-mode-alist "\\.go\\'")
(go-mode auto-mode-alist "go\\.mod\\'" go-dot-mod-mode)
(go-mode auto-mode-alist "go\\.work\\'" go-dot-work-mode)
(graphql-mode auto-mode-alist "\\.graphql\\'")
@ -137,6 +144,7 @@
(haskell-mode auto-mode-alist "\\.hsc\\'")
(haskell-mode interpreter-mode-alist "runghc")
(haskell-mode interpreter-mode-alist "runhaskell")
(haskell-tng-mode auto-mode-alist "\\.hs\\'")
(j-mode auto-mode-alist "\\.ij[rsp]$")
(j-mode auto-mode-alist "\\.ijt$" j-lab-mode)
(jade-mode auto-mode-alist "\\.jade\\'")
@ -147,12 +155,15 @@
(julia-mode auto-mode-alist "\\.jl\\'")
(lua-mode auto-mode-alist "\\.lua\\'")
(lua-mode interpreter-mode-alist "lua")
(magit-section auto-mode-alist "/git-rebase-todo\\'" git-rebase-mode)
(magit auto-mode-alist "/git-rebase-todo\\'" git-rebase-mode)
(markdown-mode auto-mode-alist "\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'")
(nginx-mode auto-mode-alist "nginx\\.conf\\'")
(nginx-mode auto-mode-alist "/nginx/.+\\.conf\\'")
(nix-mode auto-mode-alist "^/nix/store/.+\\.drv\\'" nix-drv-mode)
(nix-mode auto-mode-alist "\\flake.lock\\'" js-mode)
(nix-mode auto-mode-alist "\\.nix\\'")
(php-mode interpreter-mode-alist "php\\(?:-?[34578]\\(?:\\.[0-9]+\\)*\\)?")
(php-mode auto-mode-alist "/\\.php_cs\\(?:\\.dist\\)?\\'")
(php-mode auto-mode-alist "\\.\\(?:php\\.inc\\|stub\\)\\'")
(php-mode auto-mode-alist "\\.\\(?:php[s345]?\\|phtml\\)\\'" php-mode-maybe)
@ -178,6 +189,9 @@
(subed auto-mode-alist "\\.vtt\\'" subed-vtt-mode)
(swift-mode auto-mode-alist "\\.swift\\(interface\\)?\\'")
(systemd auto-mode-alist "\\.nspawn\\'" systemd-mode)
(systemd auto-mode-alist "[.0-9@-Z\\_a-z-]+?\\.\\(?:automount\\|busname\\|link\\|mount\\|net\\(?:dev\\|work\\)\\|s\\(?:ervice\\|lice\\|ocket\\|wap\\)\\|t\\(?:arget\\|imer\\)\\)\\'" systemd-mode)
(systemd auto-mode-alist "\\.#\\(?:[.0-9@-Z\\_a-z-]+?\\.\\(?:automount\\|busname\\|link\\|mount\\|net\\(?:dev\\|work\\)\\|s\\(?:ervice\\|lice\\|ocket\\|wap\\)\\|t\\(?:arget\\|imer\\)\\)\\|override\\.conf\\)[[:xdigit:]]\\{16\\}\\'" systemd-mode)
(systemd auto-mode-alist "/systemd/[^z-a]+?\\.d/[^/]+?\\.conf\\'" systemd-mode)
(tuareg auto-mode-alist "\\.ml[ip]?\\'" tuareg-mode)
(tuareg auto-mode-alist "\\.eliomi?\\'" tuareg-mode)
(tuareg interpreter-mode-alist "ocamlrun" tuareg-mode)