Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Have a "ebib-notes-display-note-symbol" function for checking presence of files associated with a biblatex entry #291

Open
sync0 opened this issue Mar 2, 2024 · 4 comments

Comments

@sync0
Copy link

sync0 commented Mar 2, 2024

Just like ebib-notes-display-note-symbol checks for the presence of notes associated with a biblatex entry and displays a symbol in the index view, it would be very nice to have similar functionality for the presence of attachments in the file biblatex field. Considering that the way notes functionality is implemented in Ebib is quite complex, just the indicator for the presence of files in the file field (for example, the way the helm-bibtex package does it) would suffice.

Thank you so much for your package.

@Hugo-Heagren
Copy link
Contributor

I don't know if this will help, but I have this in my config:

(defun my/ebib-display-status-icon (test icon action &optional button-data)
  "If TEST, display ICON with ACTION and BUTTON-DATA.

TEST can be:
- a symbol for a function, which will be called with no args.
- a variable
Either way, after calling/evaluation, ICON is displayed only if the
result is non-nil.

ICON should a single-character string.

ICON's text-property 'action is set to this ACTION. It is run
when the icon is clicked.

ICON's text-property 'button-data is set to BUTTON-DATA.

See info node `(elisp) Manipulating Buttons' for a description of how
these properties work."
  (if (if (functionp test) (funcall test) test)
      (propertize icon
		  'mouse-face 'highlight
		  'button t
		  'follow-link t
		  'category t
		  'keymap button-map
		  'button-data button-data
		  'action action)
    (let ((width (string-pixel-width icon)))
      ;; This has to be only 1 character! (as does the max width of
      ;; the file index column)
      (propertize " " 'display `(space . (:width (,width)))))))

(defun my/ebib-display-file-status (_ key db)
  "Display icon if entry has a file.

Different icons are used for different values of the `file' field:
- if there are multiple files, then `files-o' is displayed.
- otherwise, the filename is passed to `all-the-icons-icon-for-file',
  which returns an icon appropriate to the filetype.

On non-graphical displays, this function returns \"F\" for all
files.

Whatever string is returned, it is always red."
  (let* ((file-val (ebib-get-field-value
		    "file" key db 'noerror 'unbraced 'xref))
	 (icon (my/ebib-display-status-icon
		file-val ;; `my/ebib-display-status-icon' test whether to display
		;; `my/ebib-display-status-icon': icon
		(if (display-graphic-p)
		    (if file-val
			(let* ((file-list (ebib--split-files file-val)))
			  (if (cadr file-list)
			      ;; Many files case
			      (all-the-icons-faicon
			       "files-o" :face 'all-the-icons-red)
			    ;; One file case: get appropriate icon
			    (all-the-icons-icon-for-file
			     (car file-list) :face 'all-the-icons-red)))
		      ;; No file case
		      " ")
		  ;; Non-graphical case
		  (propertize "F" 'face '(:foreground red)))
		'ebib-view-file)) ;; `my/ebib-display-status-icon': button action
	 (icon-width (string-pixel-width icon)))
    ;; Return icon (unmodified) followed by a space, propertized
    ;; such that the whole string is the same width as the widest
    ;; char in `all-the-icons-data/file-icon-alist'.
    ;; `my/all-the-icons-file-max-width' is declared as a global
    ;; because it takes quite a while to compute (and is unlikely to
    ;; change while using ebib)
    (concat
     icon
     (propertize
      " "
      'display `(space . (:width (,(- my/all-the-icons-file-max-width icon-width))))))))

Then my ebib-field-transformation-functions contains ("File" . my/ebib-display-file-status) and my ebib-index-columns contains ("File" 2 nil).

The upshot of this is that a clickable icon for a file is displayed in the index, for just for the entries which have files. The all-the-icons-* stuff makes sure that the icon matches the file type, but you could remove that if you don't need it.

@sync0
Copy link
Author

sync0 commented Mar 2, 2024

Awesome! Thank you so much. This is exactly what I was looking for.

@joostkremers
Copy link
Owner

Well, if this is exactly what you're looking for, then there are already at least two people interested in this feature. 😄 If I find some time, I'll add it to Ebib, or @Hugo-Heagren , if you want to create a PR, that would be great, too.

@sync0
Copy link
Author

sync0 commented Mar 3, 2024

For the sake of completion to this thread, taking as clue the answer kindly provided by @Hugo-Heagren, this is the code I ended up using:

(defun sync0-ebib-has-existing-files-p (file-val)
  "Check if at least one file specified in FILE-VAL exists."
  (when file-val
    (if (string-match ";" file-val)
	(let* ((files-list (split-string file-val ";"))
	       (corrected-list (mapcar (lambda (file)
                                         (if (string-match ":\\(.*\\)\\:[^.]*$" file)
                                             (match-string 1 file)
                                           file))
                                       files-list)))
          (seq-some #'file-exists-p corrected-list))
      (let ((corrected-file (if (string-match ":\\(.*\\)\\:[^.]*$" file-val)
                                (match-string 1 file-val)
                              file-val)))
        (file-exists-p corrected-file)))))

(defun sync0-ebib-display-file-status (_ key db)
  "Return 'F' if at least one file associated with the entry exists."
  (let ((file-val (ebib-get-field-value "file" key db 'noerror 'unbraced 'xref)))
    (if (sync0-ebib-has-existing-files-p file-val)
	(propertize "F" 'face '(:weight bold))
      "")))

The reason being that I specify the file field as:

  file = {:/home/sync0/Gdrive/cabinet/23346ce.pdf:PDF;:/home/sync0/Gdrive/cabinet/23346ce.epub:EPUB},

in order for it to be compatible with the specification of multiple files in helm-bibtex (though I use ivy).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants