-
Notifications
You must be signed in to change notification settings - Fork 74
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
Make bibtex-completion (more) interactive #361
Conversation
bb3d3e6
to
389ccf3
Compare
389ccf3
to
71429d2
Compare
99f5349
to
233686c
Compare
Going to copy @myshevchuk here too, just in case he has time for input. |
Makes core action-functions interactive by adding a new `bibtex-completion--read` function, with configurable completion systems. The default uses `completing-read`.
233686c
to
4813891
Compare
…o interactive-bibtex-completion
25a604f
to
4fa15d0
Compare
Change to cl-loop, and propertize candidates string to use bibtex-completion-candidates, but to display using bibtex-completion-format-entry.
0ebfea9
to
8516cfa
Compare
I'm dealing with a number of emergencies that require my full attention (nothing life threatening). I will therefore mute this and related threads for a week or two. This doesn't mean that I lost interest. Thanks for your understanding. |
5754c3d
to
9fb5546
Compare
So here's what I'm thinking: We should close PR for now. Why? I think the ideas embedded in it are sound, but for sure it would involve a change in the relations among the three packages here. So I'm pretty sure you won't want to consider that for the short-term, and you may not even want to adopt it for the long-term. Meanwhile, I've gotten comfortable enough with all of this to get much farther along on the independent project, which might benefit from that independence (with its own repo, issue tracker, discussion board, etc.). OTOH, the code is here for later reference. So if you should want to incorporate the ideas in future releases, it will be easy enough to do. It's all pretty simple, after all, but there would be some decisions to make, on questions already raised (command names, for example, and whether worthwhile to refactor Let me know if I have that right when you get a chance @tmalsburg. |
Also, I added some code to allow people to optionally use icon fonts for the pdf and note (and link, which I added) symbols, but I couldn't get bibtex-completion to use them, perhaps because these are propertized strings? I was wanting to experiment with whether it was possible to use the icon fonts, and ensure proper alignment with them. If the latter is true, it could be nice to allow this with bibtex-completion et al. As in: (setq! bibtex-completion-pdf-symbol (all-the-icons-icon-for-file "foo.pdf" :face ;'all-the-icons-dred)) EDIT: this on its own won't work, as at least (defcustom bibtex-actions-icon
`((pdf . (,bibtex-completion-pdf-symbol . " "))
(note . (,bibtex-completion-notes-symbol . " "))
(link . (,bibtex-actions-link-symbol . " ")))
"Configuration alist specifying which symbol or icon to pick for a bib entry.
This leaves room for configurations where the absense of an item
may be indicated with the same icon but a different face."
:group 'bibtex-actions
:type '(alist :key-type string
:value-type (choice (string :tag "Icon")))) |
I'm going to close this, and encourage instead merging the other smaller PRs I've submitted (though the title shortening one is the least important to me; just thought it might be helpful to someone). As I said above, I do think the ideas here are worth considering longer term. |
I see there is a separate package now ( |
Yep; as I dug into the code, I decided better to have a separate
project and instead submit small PRs to improve pieces.
|
First thanks @tmalsburg for this great package!! Recently I switched from |
@mohkale - I forgot about this post of your's above. How do you see this applying to bibtex-actions? On what would you narrow? Daniel actually submitted a patch to emacs to add grouping support, which was merged yesterday. |
You could narrow on what you specified (presence of PDF, or notes). I've actually never needed this but I just set it up so that you can narrow on the kind of bibtex entry it is. (require 'bibtex-completion)
(defvar consult-bibtex-history+ nil
"History for `consult-bibtex+'.")
(defvar consult-bibtex-default-action+ 'consult-bibtex-insert-pdftools-link
"The default action for the `consult-bibtex+` command.")
(defvar consult-bibtex-narrow+
'((?b . "Book")
(?u . "Unpublished")
;; Fallback for when none of the others apply.
(?o . "Other"))
"Narrowing configuration for `consult-bibtex+'.")
(defun consult-bibtex-candidates+ ()
(cl-loop
for cand in (bibtex-completion-candidates)
with cand-str = nil
do (setq cand-str
(bibtex-completion-format-entry (cdr cand) (1- (frame-width))))
;; Add a `consult--type' property for narrowing support.
do (add-text-properties 0 1
`(consult--type
,(or
(when-let ((type (bibtex-completion-get-value "=type=" cand)))
(car (rassoc (capitalize type) consult-bibtex-narrow+)))
(car (rassoc "Other" consult-bibtex-narrow+)))
consult--candidate
,(bibtex-completion-get-value "=key=" cand))
cand-str)
collect cand-str))
(defun consult-bibtex-read-entry+ (&optional arg local-bib)
(when arg
(bibtex-completion-clear-cache))
(bibtex-completion-init)
(let* ((candidates (consult-bibtex-candidates+))
(preselect
(when-let ((key (bibtex-completion-key-at-point)))
(cl-find-if (apply-partially #'string-equal key) candidates))))
(consult--read candidates
:prompt (format "BibTeX entries%s: " (if local-bib " (local)" ""))
:require-match t
:category 'bibtex-completion
:lookup 'consult--lookup-candidate
:default preselect
:title (consult--type-title consult-bibtex-narrow+)
:narrow (consult--type-narrow consult-bibtex-narrow+)
:history '(:input consult-bibtex-history+))))
(defun consult-bibtex+ (&optional arg local-bib)
(interactive "P")
(when-let ((entry (consult-bibtex-read-entry+ arg local-bib)))
(if consult-bibtex-default-action+
(funcall-interactively consult-bibtex-default-action+ entry)
(warn "`consult-bibtex-default-action+' is unassigned.")))) Now if I run the command you can see entries of type book are grouped together and entries of type unpublished are also grouped together. I've set it up so anything without a type I'd like to narrow on gets put into the And I can use consult to narrow onto a specific group type such that none of the other candidates are visible. This is of course a very simplistic example. I can also set it up so that I can narrow on notes or pdfs (I plan to now). But as a demonstration it should be enough. While narrowing is consult specific, you can group candidates with completing-read by using the metadata property. (completing-read "Prompt: "
(lambda (str pred action)
(if (eq action 'metadata)
`((x-title-function . GROUP-FUNCTION))
(complete-with-action action cands str pred))))
Incidentally I don't think the group-function minad submitted allows narrowing. All it does is let completion frontends like selectrum or bibtex group candidates together based on it, which could be enough to meet what you intended. Also I think this has been around for a while, minads recent changes were just changing the name of x-title-function to something like group-function (you can look that up I'm sure). EDIT: I've added pdf and note based narrowing, now I can quickly see only the bibtex entries that have note files. |
That's what I was thinking. So it's another way to handle what we now do with "initial-value" filters.
Got it.
Yes; all correct. But it now formalizes grouping as a part of completing-read. Edit: see, for example, this commit or vertico.
What do you think of the UX compared to the approach I took in bibtex-actions? Do you see an advantage? |
I don't really use bibtex-completion, although I'm loving all the progress you've made with it so far. I feel like your implementation is better for regular commands. If users use |
I'll have to experiment with that consult-based filtering. We also tried to address this issue here: emacs-citar/citar#120. This uses a combination of "future" history and "predefined" search terms. But I'm not sure if this was the best approach or not, how it compares to your approach, etc.
I have thought about a single entry point, but not sure the point given the current design, given one could just write an alias to whatever you want and use that with embark. |
If you have a bunch of commands that work on the same type of objects, Embark let's you pick any single one of them and think of it as the "single entry point". For example, before writing Embark I used to use So for bibtex-actions, whichever command is the the one you use most often, think of that one as the entry point and then run the others as actions. |
@oantolin That's exactly what I do and meant by a millions "ways to use it". Apologies if that wasn't clear enough, although thanks for clarifying the point. 😄. |
Sorry, @mohkale, I think I read too quickly and didn't realize that's what you meant! |
@bdarcus Can this package load the |
BTW, I've been active in helping get native org-cite functionality added to org-mode. This sort of feature would probably ideally be generalized to include org and also pandoc files, including csljson bib files. |
Nope. I rarely use the in-file bibtex stuff and when I do it's only one or two of them. Is there a reason you don't want to create a propper bibtex file for them @linwaytin? In my case I keep everything I've ever read or intend to read in bibtex files because that makes it easier to reference them and pull up my notes for them. You can always make a local bibtex file for whatever your working on and use directory-local-variables to make |
@mohkale I believe @linwaytin is talking about using a bibtex file, and is wondering if bibtex-actions can figure out which bibtex file it is by looking for a |
Oh, my bad, I read that too quickly 😓. I don't think it can, this seems more like like the kinda thing local-variables should be used for. |
I disagree, looking at the current buffer to figure out which bibtex file to use seems like an obvious and great solution. Something simple like this might be enough: (defvar old--bibtext-files nil)
(defun toggle-local-bibliography ()
"Toggle whether to use the local bibliography."
(interactive)
(if old--bibtext-files
(progn
(setq bibtex-files old--bibtext-files
old--bibtext-files nil)
(message "Using global bibliography %s" bibtex-files))
(save-excursion
(goto-char (point-min))
(if (search-forward-regexp "\\\\bibliography{\\([^}]+\\)}" nil t)
(let ((bib (expand-file-name (concat (match-string 1) ".bib"))))
(setq old--bibtext-files bibtex-files bibtex-files (list bib))
(message "Using %s" bib))
(message "No local bibliography found"))))) |
I think that advanced bibtex users tend to have a few large centralized bibtex files, with all the references they might use, maybe one file per subfield or something like that.; but many naive bibtex users (and I'm still at this stage!), tend to use one bib file per paper. The naive strategy seems inferior in the long run, but at least at first, the need to fix all the keys to be unique and keep things tidy seems overwhelming and it just feels easier to reduce the scope of the problem to the references of a single paper. People following the naive strategy tend to copy and paste references from the bib files of older papers into the new bib file, and then just search for the remaining references they need as they go along. People using the one bib-file-per-paper approach probably don't even have a good setting for |
Yes, I am not an advanced bibtex user. I currently use a bib file for a project. |
I played a bit with narrowing using
Yes, but so are initial-values and future history. One can simply delete the initial-value from the prompt, for example. The narrowing UI is arguably a bit more elegant though. |
Yes. I seem to have misunderstood how that works there. I thought the collection was filtered before completing-read but it looks like its filtered afterwards in which case their mostly equivalent. |
Here's how the "presets" feature works. If you add this ... (setq bibtex-actions-presets '("book" "article" "inbook")) ... you can then access those by doing It doesn't, however, match against the type field, of course, but against the whole candidate string. But the advantage is you could set those to a regexp to grab, for example, all articles published since 2019, or whatever. |
Introduction
Over the last year, there has been a lot of activity on packages that are built around the emacs
completing-read
API. Designed for compatibility and modularity, but in collaboration, these tools together provide users flexibility and excellent functionality.This PR provides an alternative approach to (really just adapts code from) #355 as a means to offer bibtex-completion functionality to emacs vertically-oriented completion systems using
completing-read
, such asicomplete-vertical
andselectrum
(see #353).The changes are minor, adding only about 70 very simple LOC. It follows @minad's advice to make the core functions interactive, using a new
bibtex-completion--read
function, which allows for configurable completion systems.By default, this function uses
completing-read
, which is already used inbibtex-completion
in a few places.But the intention is that one could use another function there, as the default function is bound to
bibtex-completion-read-backend
viafset
.So
ivy-bibtex
andhelm-bibtex
could, if there was value in this, instead use functions based onivy-read
andhelm-read
respectively (though this appears to be unnecessary, as they seem to work fine as is). One could even write a differentcompleting-read
function, if one wanted to modify the behavior locally, or in a separate package.Also adds a keymap;
bibtex-completion-map
.I do think this demonstrates how small a footprint this sort of change would introduce, while providing more flexibility for users and developers, but without impacting the packages that depend on it.
Status
Everything seems to work correctly.
The basic
bibtex-completion--read
function works, and all of the action functions included in the keymap now use it.Here's a screenshot showing the most basic, default, installation, with
icomplete-vertical
:With this setup, you only have access to the default command; there are no other actions/commands available.
Adding embark, however, adds that support, and so is strongly recommended. Binding the keymap to
embark-act
like so ...... will get you quick and easy access to additional actions, as well as the ability to snapshot sub collections and act on those as with
ivy-occur
.A full set of
completing-read
compatible packages to get, IMHO, the best experience using this includes the following:Here is with the above installed and configured (though consult is not strictly necessary).
Next Steps?
I could use help on the following (which will be valuable even if we go with #355 instead):
ivy-bibtex
andhelm-bibtex
embark
(looking into embark-direct-action-mode, tablist, and hiding the general embark commands) and without.Finally, while I think out-of-scope for this PR:
helm-bibtex
andivy-bibtex
use an adaptedbibtex-completion--read
, and if so, implementing that. As I say above, the PR so far does not impact the functionality of thehelm-bibtex
andivy-bibtex
actions. Thebibtex-completion
commands also work, at least withinhelm
(I haven't tested withivy
).Testing
If you want to test this, but don't have the selectrum et al packages installed, a quick and simple option I recommend using
emacs -Q
is one of the selectrum test scripts, preferably the selectrum-prescient one.All you need to do, then, is eval this code:
Upon running one of the commands, and narrowing the candidates, you can then run
embark-act
(in the test scripts, it is bound toM-o
).Concerns
@tmalsburg has raised some reasonable concerns, which we can summarize as:
#355 (comment)
#355 (comment)
Issue 1 I can't really assess, but is obviously the more serious issue. Hopefully this PR addresses this concern.
On 2, the function names are mostly OK, with two obvious issues:
bibtex-completion-open-any
; I actually think it's fine, and more importantly, have a hard time coming up with something better (maybe omit the "any"?). But if we do, we could use the same solution as 1?I suppose if we wanted to be aggressive, we could also think about:
bibtex-completion-open-any
->bibtex-completion-open
bibtex-completion-open-url-or-doi
->bibtex-completion-open-link
bibtex-completion-open-pdf
(per change noted above)And for that matter consolidating around "insert" and "open" as the key action verbs.
Not sure, but it seems like something like
make-obsolete
could work?Relation to #355
These would be functionally the same; just different command name prefixes.
@mtreca started #355, but this code is further-developed and feature-complete. I have merged the two code bases here as an experiment.
Decisions
After working on this, I have concluded this should come down to a choice between two options:
Each option is workable, I think, and each has trade-offs.
I suppose there's also a third option, which is merging this into an experimental branch for longer term consideration, and also doing the separate package now.