emacs-citar / citar

Emacs package to quickly find and act on bibliographic references, and edit org, markdown, and latex academic documents.
GNU General Public License v3.0
501 stars 54 forks source link

Customizable `citar-add-file-to-library` #804

Closed mpedramfar closed 11 months ago

mpedramfar commented 12 months ago

Is your feature request related to a problem? Please describe. Currently, the behavior of the function citar-add-file-to-library is not that customizable. For example:

Describe the solution you'd like One way to implement it would be to have something like this:

(defun citar-save-file (fun citekey name)
  "FUN is a function that takes one argument, DESTFILE, and saves the file to DESTFILE.
NAME is the initial name of the source file."
  (let* ((directory (if (cdr citar-library-paths)
                        (completing-read "Directory: " citar-library-paths)
                      (car citar-library-paths)))
         (extension (or (and (stringp name) (file-name-extension name))
                        (read-string "File extension: ")))
         (destfile (expand-file-name citekey directory))
         (destfile (if (string-empty-p extension)
                       destfile
                     (concat destfile "." extension))))
    (funcall fun destfile)))

(setq citar-save-file-function #'citar-save-file) ;; this can be a customizable variable

(defun citar-add-file-to-library (citekey)
  "Add a file to the library for CITEKEY.
The FILE can be added from an open buffer, a file path, or a
URL."
  (interactive (list (citar-select-ref)))
  (citar--check-configuration 'citar-library-paths)
  (unless citar-library-paths
    (user-error "Make sure `citar-library-paths' is non-nil"))
  (let (fun name)
    (pcase (read-char-choice "Add file from [b]uffer, [f]ile, or [u]rl? " '(?b ?f ?u))
      (?b
       (let ((buf (read-buffer "Add file buffer: " (current-buffer))))
         (setq name (and buffer-file-name (file-name-nondirectory buffer-file-name)))
         (setq fun (lambda (destfile)
                     (with-current-buffer buf
                       (write-file destfile 'confirm))))))
      (?f
       (let* ((file (read-file-name "Add file: " nil nil t)))
         (setq name (file-name-nondirectory file))
         (setq fun (lambda (destfile)
                     ;; last arg integer means to confirm before overwriting
                     (copy-file file destfile 1)))))
      (?u
       (let* ((url (read-string "Add file URL: ")))
         ;; TODO: Use Content-Type HTTP response header to guess file extension
         (setq name (url-file-nondirectory url))
         (setq fun (lambda (destfile)
                     (url-copy-file url destfile 1))))))
    (funcall citar-save-file-function fun citekey name)))
mpedramfar commented 12 months ago

Actually, I don't see a use case for passing name to the save function, only extension should be enough. Besides, the regular expression used to find the extension in file-name-extension is not identical to the one used in url-file-extension.

bdarcus commented 12 months ago

In general, I don't have a problem with the basic request, since customizability is key design goal of citar.

OTOH, I don't really have time to implement this myself ATM, and it's easy enough to write your own command.

Or if you like, you could submit a PR, since you've already thought about the implementation details. That makes it much easier to evaluate and comment on the details on our end.

mpedramfar commented 12 months ago

Great! I'll make a PR soon.