summaryrefslogtreecommitdiff
path: root/lisp/recentf.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/recentf.el')
-rw-r--r--lisp/recentf.el196
1 files changed, 119 insertions, 77 deletions
diff --git a/lisp/recentf.el b/lisp/recentf.el
index 7a4b589e457..b80ee3dd7d8 100644
--- a/lisp/recentf.el
+++ b/lisp/recentf.el
@@ -1,4 +1,4 @@
-;;; recentf.el --- setup a menu of recently opened files -*- lexical-binding: t -*-
+;;; recentf.el --- keep track of recently opened files -*- lexical-binding: t -*-
;; Copyright (C) 1999-2022 Free Software Foundation, Inc.
@@ -23,10 +23,19 @@
;;; Commentary:
-;; This package maintains a menu for visiting files that were operated
-;; on recently. When enabled a new "Open Recent" submenu is
-;; displayed in the "File" menu. The recent files list is
-;; automatically saved across Emacs sessions.
+;; This package maintains a list of recently opened files and makes it
+;; easy to visit them. The recent files list is automatically saved
+;; across Emacs sessions.
+
+;; There are three ways to access recent files:
+;;
+;; (1) `M-x recentf-open' prompts for a recently opened file.
+;;
+;; (2) When this mode is enabled, a new "Open Recent" submenu is
+;; displayed in the "File" menu.
+;;
+;; (3) `M-x recentf-open-files' lists recently visited files in a
+;; buffer.
;; You can customize the number of recent files displayed, the
;; location of the menu and other options. Type:
@@ -45,16 +54,17 @@
;;; Internal data
;;
(defvar recentf-list nil
- "List of recently opened files.")
+ "List of recently opened files for `recentf-mode'.")
-(defsubst recentf-enabled-p ()
- "Return non-nil if recentf mode is currently enabled."
+(defun recentf-enabled-p ()
+ "Return non-nil if `recentf-mode' is currently enabled."
(memq 'recentf-save-list kill-emacs-hook))
+
;;; Customization
;;
(defgroup recentf nil
- "Maintain a menu of recently opened files."
+ "Maintain a list of recently opened files."
:version "21.1"
:group 'files)
@@ -159,7 +169,7 @@ If nil add it at end of menu (see also `easy-menu-add-item')."
(const :tag "Last" nil))
:set 'recentf-menu-customization-changed)
-(defcustom recentf-menu-action 'find-file
+(defcustom recentf-menu-action #'find-file
"Function to invoke with a filename item of the recentf menu.
The default is to call `find-file' to edit the selected file."
:group 'recentf
@@ -168,7 +178,7 @@ The default is to call `find-file' to edit the selected file."
(defcustom recentf-max-menu-items 10
"Maximum number of items in the recentf menu."
:group 'recentf
- :type 'integer)
+ :type 'natnum)
(defcustom recentf-menu-filter nil
"Function used to filter files displayed in the recentf menu.
@@ -237,6 +247,8 @@ This item will replace the \"More...\" item."
(defcustom recentf-auto-cleanup 'mode
"Define when to automatically cleanup the recent list.
+That is, remove duplicates, non-kept, and excluded files.
+
The following values can be set:
- `mode'
@@ -284,7 +296,7 @@ If `file-name-history' is not empty, do nothing."
(make-obsolete-variable 'recentf-load-hook
"use `with-eval-after-load' instead." "28.1")
-(defcustom recentf-filename-handlers nil
+(defcustom recentf-filename-handlers '(abbreviate-file-name)
"Functions to post process recent file names.
They are successively passed a file name to transform it."
:group 'recentf
@@ -294,7 +306,8 @@ They are successively passed a file name to transform it."
(choice
(const file-truename)
(const abbreviate-file-name)
- (function :tag "Other function")))))
+ (function :tag "Other function"))))
+ :version "29.1")
(defcustom recentf-show-file-shortcuts-flag t
"Non-nil means to show \"[N]\" for the Nth item up to 10.
@@ -309,14 +322,14 @@ used as shortcuts to open the Nth file."
(memq system-type '(windows-nt cygwin))
"Non-nil if recentf searches and matches should ignore case.")
-(defsubst recentf-string-equal (s1 s2)
+(defun recentf-string-equal (s1 s2)
"Return non-nil if strings S1 and S2 have identical contents.
Ignore case if `recentf-case-fold-search' is non-nil."
(if recentf-case-fold-search
(string-equal (downcase s1) (downcase s2))
(string-equal s1 s2)))
-(defsubst recentf-string-lessp (s1 s2)
+(defun recentf-string-lessp (s1 s2)
"Return non-nil if string S1 is less than S2 in lexicographic order.
Ignore case if `recentf-case-fold-search' is non-nil."
(if recentf-case-fold-search
@@ -371,7 +384,7 @@ See also the option `recentf-auto-cleanup'.")
;;; File functions
;;
-(defsubst recentf-push (filename)
+(defun recentf-push (filename)
"Push FILENAME into the recent list, if it isn't there yet.
If it is there yet, move it at the beginning of the list.
If `recentf-case-fold-search' is non-nil, ignore case when comparing
@@ -394,7 +407,7 @@ returned nil."
(error nil))
name))
-(defsubst recentf-expand-file-name (name)
+(defun recentf-expand-file-name (name)
"Convert file NAME to absolute, and canonicalize it.
NAME is first passed to the function `expand-file-name', then to
`recentf-filename-handlers' to post process it."
@@ -435,7 +448,7 @@ That is, if it matches any of the `recentf-keep' checks."
checks (cdr checks)))
keepit))
-(defsubst recentf-add-file (filename)
+(defun recentf-add-file (filename)
"Add or move FILENAME at the beginning of the recent list.
Does nothing if the name satisfies any of the `recentf-exclude'
regexps or predicates."
@@ -443,7 +456,7 @@ regexps or predicates."
(when (recentf-include-p filename)
(recentf-push filename)))
-(defsubst recentf-remove-if-non-kept (filename)
+(defun recentf-remove-if-non-kept (filename)
"Remove FILENAME from the recent list, if file is not kept.
Return non-nil if FILENAME has been removed."
(unless (recentf-keep-p filename)
@@ -461,10 +474,30 @@ Return non-nil if F1 is less than F2."
(recentf-string-lessp (file-name-nondirectory f1)
(file-name-nondirectory f2))
(recentf-string-lessp d1 d2))))
+
+
+;;; Open files
+;;
+
+;;;###autoload
+(defun recentf-open (file)
+ "Prompt for FILE in `recentf-list' and visit it.
+Enable `recentf-mode' if it isn't already."
+ (interactive
+ (list
+ (progn (unless recentf-mode (recentf-mode 1))
+ (completing-read (format-prompt "Open recent file" nil)
+ recentf-list nil t))))
+ (when file
+ (funcall recentf-menu-action file)))
+
+;;;###autoload
+(defalias 'recentf 'recentf-open)
+
;;; Menu building
;;
-(defsubst recentf-digit-shortcut-command-name (n)
+(defun recentf-digit-shortcut-command-name (n)
"Return a command name to open the Nth most recent file.
See also the command `recentf-open-most-recent-file'."
(intern (format "recentf-open-most-recent-file-%d" n)))
@@ -476,10 +509,10 @@ See also the command `recentf-open-most-recent-file'."
;; Define a shortcut command.
(defalias cmd
`(lambda ()
- (interactive)
+ (interactive nil recentf-dialog-mode)
(recentf-open-most-recent-file ,k)))
;; Bind it to a digit key.
- (define-key km (vector (+ k ?0)) cmd)))
+ (keymap-set km (format "%d" k) cmd)))
km)
"Digit shortcuts keymap.")
@@ -510,10 +543,6 @@ If non-nil it must contain a list of valid menu-items to be appended
to the recent file list part of the menu. Before calling a menu
filter function this variable is reset to nil.")
-(defsubst recentf-elements (n)
- "Return a list of the first N elements of the recent list."
- (seq-take recentf-list n))
-
(defsubst recentf-make-menu-element (menu-item menu-value)
"Create a new menu-element.
A menu element is a pair (MENU-ITEM . MENU-VALUE), where MENU-ITEM is
@@ -553,7 +582,7 @@ This a menu element (FILE . FILE)."
"Return a list of the first N default menu elements from the recent list.
See also `recentf-make-default-menu-element'."
(mapcar #'recentf-make-default-menu-element
- (recentf-elements n)))
+ (seq-take recentf-list n)))
(defun recentf-apply-menu-filter (filter l)
"Apply function FILTER to the list of menu-elements L.
@@ -650,7 +679,7 @@ Return nil if file NAME is not one of the ten more recent."
:help (concat "Open " value)
:active t)))))
-(defsubst recentf-menu-bar ()
+(defun recentf-menu-bar ()
"Return the keymap of the global menu bar."
(lookup-key global-map [menu-bar]))
@@ -670,59 +699,59 @@ Return nil if file NAME is not one of the ten more recent."
;;; Predefined menu filters
;;
-(defsubst recentf-sort-ascending (l)
+(defun recentf-sort-ascending (l)
"Sort the list of menu elements L in ascending order.
The MENU-ITEM part of each menu element is compared."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-string-lessp
- (recentf-menu-element-item e1)
- (recentf-menu-element-item e2)))))
+ (lambda (e1 e2)
+ (recentf-string-lessp
+ (recentf-menu-element-item e1)
+ (recentf-menu-element-item e2)))))
-(defsubst recentf-sort-descending (l)
+(defun recentf-sort-descending (l)
"Sort the list of menu elements L in descending order.
The MENU-ITEM part of each menu element is compared."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-string-lessp
- (recentf-menu-element-item e2)
- (recentf-menu-element-item e1)))))
+ (lambda (e1 e2)
+ (recentf-string-lessp
+ (recentf-menu-element-item e2)
+ (recentf-menu-element-item e1)))))
-(defsubst recentf-sort-basenames-ascending (l)
+(defun recentf-sort-basenames-ascending (l)
"Sort the list of menu elements L in ascending order.
Only filenames sans directory are compared."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-string-lessp
- (file-name-nondirectory (recentf-menu-element-value e1))
- (file-name-nondirectory (recentf-menu-element-value e2))))))
+ (lambda (e1 e2)
+ (recentf-string-lessp
+ (file-name-nondirectory (recentf-menu-element-value e1))
+ (file-name-nondirectory (recentf-menu-element-value e2))))))
-(defsubst recentf-sort-basenames-descending (l)
+(defun recentf-sort-basenames-descending (l)
"Sort the list of menu elements L in descending order.
Only filenames sans directory are compared."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-string-lessp
- (file-name-nondirectory (recentf-menu-element-value e2))
- (file-name-nondirectory (recentf-menu-element-value e1))))))
+ (lambda (e1 e2)
+ (recentf-string-lessp
+ (file-name-nondirectory (recentf-menu-element-value e2))
+ (file-name-nondirectory (recentf-menu-element-value e1))))))
-(defsubst recentf-sort-directories-ascending (l)
+(defun recentf-sort-directories-ascending (l)
"Sort the list of menu elements L in ascending order.
Compares directories then filenames to order the list."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-directory-compare
- (recentf-menu-element-value e1)
- (recentf-menu-element-value e2)))))
+ (lambda (e1 e2)
+ (recentf-directory-compare
+ (recentf-menu-element-value e1)
+ (recentf-menu-element-value e2)))))
-(defsubst recentf-sort-directories-descending (l)
+(defun recentf-sort-directories-descending (l)
"Sort the list of menu elements L in descending order.
Compares directories then filenames to order the list."
(sort (copy-sequence l)
- #'(lambda (e1 e2)
- (recentf-directory-compare
- (recentf-menu-element-value e2)
- (recentf-menu-element-value e1)))))
+ (lambda (e1 e2)
+ (recentf-directory-compare
+ (recentf-menu-element-value e2)
+ (recentf-menu-element-value e1)))))
(defun recentf-show-basenames (l &optional no-dir)
"Filter the list of menu elements L to show filenames sans directory.
@@ -743,14 +772,14 @@ optional argument NO-DIR is non-nil, or its directory otherwise."
(setq name (format "%s(%s)" name sufx)))
(push (recentf-make-menu-element name full) filtered-list))))
-(defsubst recentf-show-basenames-ascending (l)
+(defun recentf-show-basenames-ascending (l)
"Filter the list of menu elements L to show filenames sans directory.
Filenames are sorted in ascending order.
This filter combines the `recentf-sort-basenames-ascending' and
`recentf-show-basenames' filters."
(recentf-show-basenames (recentf-sort-basenames-ascending l)))
-(defsubst recentf-show-basenames-descending (l)
+(defun recentf-show-basenames-descending (l)
"Filter the list of menu elements L to show filenames sans directory.
Filenames are sorted in descending order.
This filter combines the `recentf-sort-basenames-descending' and
@@ -808,7 +837,7 @@ corresponding sub-menu items are displayed in the main recent files
menu or in the `recentf-arrange-by-rule-others' sub-menu if
defined."
:group 'recentf-filters
- :type 'number)
+ :type 'natnum)
(defcustom recentf-arrange-by-rule-subfilter nil
"Function called by a rule based filter to filter sub-menu elements.
@@ -1037,7 +1066,7 @@ That is, remove a non kept file from the recent list."
(defun recentf-cancel-dialog (&rest _ignore)
"Cancel the current dialog.
IGNORE arguments."
- (interactive)
+ (interactive nil recentf-dialog-mode)
(kill-buffer (current-buffer))
(message "Dialog canceled"))
@@ -1055,19 +1084,20 @@ Go to the beginning of buffer if not found."
(error
(goto-char (point-min)))))
-(defvar recentf-dialog-mode-map
- (let ((km (copy-keymap recentf--shortcuts-keymap)))
- (set-keymap-parent km widget-keymap)
- (define-key km "q" #'recentf-cancel-dialog)
- (define-key km "n" #'next-line)
- (define-key km "p" #'previous-line)
- km)
- "Keymap used in recentf dialogs.")
+(defvar-keymap recentf-dialog-mode-map
+ :doc "Keymap used in recentf dialogs."
+ :parent (make-composed-keymap recentf--shortcuts-keymap widget-keymap)
+ "q" #'recentf-cancel-dialog
+ "n" #'next-line
+ "p" #'previous-line
+ "C-c C-c" #'recentf-edit-list-validate
+ "C-c C-k" #'recentf-cancel-dialog)
(define-derived-mode recentf-dialog-mode nil "recentf-dialog"
"Major mode of recentf dialogs.
\\{recentf-dialog-mode-map}"
+ :interactive nil
:syntax-table nil
:abbrev-table nil
(setq truncate-lines t))
@@ -1104,6 +1134,7 @@ IGNORE other arguments."
(defun recentf-edit-list-validate (&rest _ignore)
"Process the recent list when the edit list dialog is committed.
IGNORE arguments."
+ (interactive nil recentf-dialog-mode)
(if recentf-edit-list
(let ((i 0))
(dolist (e recentf-edit-list)
@@ -1123,8 +1154,8 @@ IGNORE arguments."
(widget-insert
(format-message
(substitute-command-keys
- "Click on OK to delete selected files from the recent list.
-Click on Cancel or type \\[recentf-cancel-dialog] to cancel.\n")))
+ "Click on \"OK\" or type \\[recentf-edit-list-validate] to delete selected files from the recent list.
+Click on \"Cancel\" or type \\[recentf-cancel-dialog] to cancel.\n")))
;; Insert the list of files as checkboxes
(dolist (item recentf-list)
(widget-create 'checkbox
@@ -1337,12 +1368,18 @@ That is, remove duplicates, non-kept, and excluded files."
;;; The minor mode
;;
-(defvar recentf-mode-map (make-sparse-keymap)
- "Keymap to use in recentf mode.")
+(defvar-keymap recentf-mode-map
+ :doc "Keymap to use in `recentf-mode'.")
;;;###autoload
(define-minor-mode recentf-mode
- "Toggle \"Open Recent\" menu (Recentf mode).
+ "Toggle keeping track of opened files (Recentf mode).
+This mode maintains a list of recently opened files and makes it
+easy to visit them. The recent files list is automatically saved
+across Emacs sessions.
+
+You can use `recentf-open' or `recentf-open-files' to visit
+files.
When Recentf mode is enabled, a \"Open Recent\" submenu is
displayed in the \"File\" menu, containing a list of files that
@@ -1353,7 +1390,7 @@ to a file, and killing a buffer is counted as \"operating\" on
the file. If instead you want to prioritize files that appear in
buffers you switch to a lot, you can say something like the following:
- (add-hook 'buffer-list-update-hook 'recentf-track-opened-file)"
+ (add-hook \\='buffer-list-update-hook #\\='recentf-track-opened-file)"
:global t
:group 'recentf
:keymap recentf-mode-map
@@ -1379,8 +1416,13 @@ buffers you switch to a lot, you can say something like the following:
(define-obsolete-function-alias 'recentf-trunc-list #'seq-take "28.1")
+(defun recentf-elements (n)
+ "Return a list of the first N elements of the recent list."
+ (declare (obsolete "use `(seq-take recentf-list n)'." "29.1"))
+ (seq-take recentf-list n))
+
(provide 'recentf)
(run-hooks 'recentf-load-hook)
-
+
;;; recentf.el ends here