Add new function file-name-with-extension

* doc/lispref/files.texi (File Name Components): Document it.
* lisp/emacs-lisp/shortdoc.el (file-name): Ditto.

* lisp/files.el (file-name-with-extension): New function.
This commit is contained in:
Colin Woodbury 2021-06-30 14:07:29 +02:00 committed by Lars Ingebrigtsen
parent 1dba0ca278
commit 4f2765f6f1
5 changed files with 66 additions and 0 deletions

View file

@ -2129,6 +2129,25 @@ the period that delimits the extension, and if @var{filename} has no
extension, the value is @code{""}.
@end defun
@defun file-name-with-extension filename extension
This function returns @var{filename} with its extension set to
@var{extension}. A single leading dot in the @var{extension} will be
stripped if there is one. For example:
@example
(file-name-with-extension "file" "el")
@result{} "file.el"
(file-name-with-extension "file" ".el")
@result{} "file.el"
(file-name-with-extension "file.c" "el")
@result{} "file.el"
@end example
Note that this function will error if @var{filename} or
@var{extension} are empty, or if the @var{filename} is shaped like a
directory (i.e. if @code{directory-name-p} returns non-@code{nil}).
@end defun
@defun file-name-sans-extension filename
This function returns @var{filename} minus its extension, if any. The
version/backup part, if present, is only removed if the file has an

View file

@ -3058,6 +3058,11 @@ been added, and takes a callback to handle the return status.
---
** 'ascii' is now a coding system alias for 'us-ascii'.
+++
** New function 'file-name-with-extension'.
This function allows a canonical way to set/replace the extension of a
filename string.
+++
** New function 'file-backup-file-names'.
This function returns the list of file names of all the backup files

View file

@ -268,6 +268,9 @@ There can be any number of :example/:result elements."
:eval (file-name-extension "/tmp/foo.txt"))
(file-name-sans-extension
:eval (file-name-sans-extension "/tmp/foo.txt"))
(file-name-with-extension
:eval (file-name-with-extension "foo.txt" "bin")
:eval (file-name-with-extension "foo" "bin"))
(file-name-base
:eval (file-name-base "/tmp/foo.txt"))
(file-relative-name

View file

@ -4894,6 +4894,27 @@ extension, the value is \"\"."
(if period
"")))))
(defun file-name-with-extension (filename extension)
"Set the EXTENSION of a FILENAME.
The extension (in a file name) is the part that begins with the last \".\".
Trims a leading dot from the EXTENSION so that either \"foo\" or
\".foo\" can be given.
Errors if the filename or extension are empty, or if the given
filename has the format of a directory.
See also `file-name-sans-extension'."
(let ((extn (string-trim-left extension "[.]")))
(cond ((string-empty-p filename)
(error "Empty filename: %s" filename))
((string-empty-p extn)
(error "Malformed extension: %s" extension))
((directory-name-p filename)
(error "Filename is a directory: %s" filename))
(t
(concat (file-name-sans-extension filename) "." extn)))))
(defun file-name-base (&optional filename)
"Return the base name of the FILENAME: no directory, no extension."
(declare (advertised-calling-convention (filename) "27.1"))

View file

@ -1478,5 +1478,23 @@ The door of all subtleties!
(buffer-substring (point-min) (point-max))
nil nil)))))
(ert-deftest files-tests-file-name-with-extension-good ()
"Test that `file-name-with-extension' succeeds with reasonable input."
(should (string= (file-name-with-extension "Jack" "css") "Jack.css"))
(should (string= (file-name-with-extension "Jack" ".css") "Jack.css"))
(should (string= (file-name-with-extension "Jack.scss" "css") "Jack.css"))
(should (string= (file-name-with-extension "/path/to/Jack.md" "org") "/path/to/Jack.org")))
(ert-deftest files-tests-file-name-with-extension-bad ()
"Test that `file-name-with-extension' fails on malformed input."
(should-error (file-name-with-extension nil nil))
(should-error (file-name-with-extension "Jack" nil))
(should-error (file-name-with-extension nil "css"))
(should-error (file-name-with-extension "" ""))
(should-error (file-name-with-extension "" "css"))
(should-error (file-name-with-extension "Jack" ""))
(should-error (file-name-with-extension "Jack" "."))
(should-error (file-name-with-extension "/is/a/directory/" "css")))
(provide 'files-tests)
;;; files-tests.el ends here