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

citekey: link to BibDesk #2908

Closed
alexandreroberts opened this issue Apr 1, 2024 · 49 comments
Closed

citekey: link to BibDesk #2908

alexandreroberts opened this issue Apr 1, 2024 · 49 comments

Comments

@alexandreroberts
Copy link

Describe the solution you'd like
As described in a different feature request a year ago that I'm finally following up on, I'd like to be able to type a single command to have vimtex open the bibentry for the citekey under the cursor in BibDesk (on MacOS). This would of course only work when the latex project open at the time refers to a .bib file.

Additional context
I briefly summarized the protocol for interacting with BibDesk here.

Sorry that is has taken me so long to open the feature request! I hope this is feasible without too much trouble.

@alexandreroberts
Copy link
Author

To be clear: for my purposes, it would also be fine for the bib file used to be simply the one that is open in BibDesk at the time, which I think might be the default behavior of open x-bdsk://citekey (command referenced here).

@lervag
Copy link
Owner

lervag commented Apr 28, 2024

I'm finally thinking about this one. So, my first thought or question is how this feature relates to the current context menu, i.e. :VimtexContextMenu - mapped to \la by default. I could see this feature implemented as part of the citation context. It would imply this workflow:

  1. Keep cursor above a cite command.
  2. Press \la to open context menu.
  3. Select "Open in BibDesk" to open it in BibDesk.

Something like this:

image

I've mapped the context menu to <cr> personally, so for me this would be two key strokes: first <cr>, then a number, e.g. 6.

lervag added a commit that referenced this issue Apr 28, 2024
@lervag
Copy link
Owner

lervag commented Apr 28, 2024

I've pushed initial support for it in the manner suggested above. Please test.

Also, I'm curious, I would want to only show "Open in BibDesk" if BibDesk is available. For Zotero, I did this with if executable('zotero'), so, what is the executable name for bibdesk on mac? I.e., if you open a terminal, how do you start bibdesk?

@alexandreroberts
Copy link
Author

alexandreroberts commented Apr 28, 2024 via email

@alexandreroberts
Copy link
Author

PS - Sorry, I added my last comment via email without realizing that you had followed it up by implementing what you proposed. I will test that and get back to you.

@alexandreroberts
Copy link
Author

Ah, and I see from the image that I misunderstood how you were proposing to use the context menu -- sorry about that too.

@lervag
Copy link
Owner

lervag commented Apr 28, 2024

No problem. I think this is, at least, a useful first step. Let's first make it work as expected, because I think it makes a nice addition regardless. Then after, we can consider making a shortcut - either included in VimTeX or as a personal advanced config.

While testing this, you could make a small temporary project with a smaller bib file. But I would be interested in hearing if the problem with slow bibfiles may have improved since the last time you tried that.

Are you using Neovim or Vim?

@alexandreroberts
Copy link
Author

I have tested the context menu approach, and it works as expected. Thank you! The context menu loaded quickly enough (not super-fast, but not at all sluggishly; also, for me, there were only three options).

Screenshot 2024-04-28 at 7 52 42 PM

For my specific purposes, this approach still has a couple disadvantages:

  1. Unnecessary step. It takes an extra step, as I mentioned in the earlier comment. Given that I will always be choosing the BibDesk option, there is no need (for me) to spend the extra CPU time, the extra second of waiting for the menu, and the extra keystroke. I would much rather type my shortcut and jump straight to BibDesk.
  2. Relatively inflexible. This only works (by design, I think) on citekeys that appear in files that Vimtex can identify as included on a project whose main tex file calls a bib file that includes those citekeys. This shouldn't be a problem for most people with simple, one-file projects. But for me, it is a problem. I am writing a book, and often I want to compile one or two chapters at a time without compiling the rest of the book, so I comment out the \include commands that call the rest of the chapter files. But while I work on the chapters I am focusing on, I often want to add notes and text to other chapter files -- above all bibliographical notes! This means that I often want to work with citekeys in files that are "orphaned," as it were, such that Vimtex cannot associate any bib file with them. Ideally, there would be a way to set a vimtex option to dispense with worrying about which bib file the citekey comes from and instead just ask BibDesk to jump to the entry for the citekey in question.

Related to this second point is a different issue that I have been meaning to ask about but which is tangled up with this because I think both involve defining what strings count as citekeys: currently, vimtex needs to know which bib package (e.g., BibLaTeX) is being called in order to extend citekeys to include the arguments of cite commands like \Volcite{}[]{citekey}. Because of this, in those same orphaned files, vimtex does not highlight those commands as I would like them to be highlighted. Perhaps there could be another vimtex option that tells vimtex to simply use all of the biblatex-chicago regexes that you implemented for me without worrying about whether biblatex-chicago is called by the project? Then I imagine that it wouldn't take much for those citekeys to be recognized as such for the purposes of linking to BibDesk.

@alexandreroberts
Copy link
Author

P.S. I am using NeoVim.

@lervag
Copy link
Owner

lervag commented Apr 28, 2024

I have tested the context menu approach, and it works as expected. Thank you! The context menu loaded quickly enough (not super-fast, but not at all sluggishly;

Good to hear. Then I think we'll keep this regardless of future work. But it would be nice if you could answer my other question from earlier. Repeated for convenience:

Also, I'm curious, I would want to only show "Open in BibDesk" if BibDesk is available. For Zotero, I did this with if executable('zotero'), so, what is the executable name for bibdesk on mac? I.e., if you open a terminal, how do you start bibdesk?

also, for me, there were only three options).

Yes, the context menu tries to only show relevant options. It depends on the available data from your bibentry. I use Zotero and I often add both URL's and pdf files to my library, and Zotero is able to make that readily available in my synchronized bib entries.

For my specific purposes, this approach still has a couple disadvantages: …

Before considering if I can somehow make this part of VimTeX, here is something you can use in your own personal config:

function! OpenInBibDesk() abort
  let l:cmd_re = '\v%(%(\a*cite|Cite)\a*|bibentry|%(text|block|%(for|hy)\w+)cquote)'
  let l:cmd = vimtex#cmd#get_current()
  if empty(l:cmd)
        \ || l:cmd.name[1:] !~# l:cmd_re
        \ || len(l:cmd.args) < 1
        \ || len(l:cmd.args) > 2
    return
  endif

  let l:text = l:cmd.args[0].text
  if len(l:cmd.args) == 2
    let l:text .= ',' .. l:cmd.args[1].text
  endif
  let l:cites = split(l:text, ',\s*')

  let l:word = expand('<cword>')
  if index(l:cites, l:word) >= 0
    let l:selected = l:word
  else
    let l:selected = l:cites[0]
  endif

  if !empty(l:selected)
    call vimtex#util#www('x-bdsk://' .. l:selected)
  endif
endfunction

nnoremap <localleader>aa :call OpenInBibDesk()<cr>

This is Vimscript, so you need to put it e.g. in your personal ftplugin/tex.vim file or perhaps in after/ftplugin/tex.vim. The after is not important here, both locations will work well.

  1. Relatively inflexible. This only works (by design, I think) on citekeys that appear in files that Vimtex can identify as included on a project whose main tex file calls a bib file that includes those citekeys.

Yes, that is right. Although "inflexible", I would argue it is sort of the expected for the current idea of the context menu.

But for me, it is a problem. I am writing a book, and often I want to compile one or two chapters at a time without compiling the rest of the book, so I comment out the \include commands that call the rest of the chapter files. But while I work on the chapters I am focusing on, I often want to add notes and text to other chapter files -- above all bibliographical notes! This means that I often want to work with citekeys in files that are "orphaned," as it were, such that Vimtex cannot associate any bib file with them. Ideally, there would be a way to set a vimtex option to dispense with worrying about which bib file the citekey comes from and instead just ask BibDesk to jump to the entry for the citekey in question.

Notice, even if your chapters are commented out from your main file, you can still have them recognize your main file and thus make both the citations and syntax stuff work seamlessly. There are several ways to do this, see :help vimtex-multi-file for the complete list of methods for specifying/locating the main file. The easiest is perhaps to use the TeX root directive, where you add something like the following to the top of your files:

%! TeX root: ../main.tex

Related to this second point is a different issue that I have been meaning to ask about but which is tangled up with this because I think both involve defining what strings count as citekeys: currently, vimtex needs to know which bib package (e.g., BibLaTeX) is being called in order to extend citekeys to include the arguments of cite commands like \Volcite{}[]{citekey}. Because of this, in those same orphaned files, vimtex does not highlight those commands as I would like them to be highlighted. Perhaps there could be another vimtex option that tells vimtex to simply use all of the biblatex-chicago regexes that you implemented for me without worrying about whether biblatex-chicago is called by the project? Then I imagine that it wouldn't take much for those citekeys to be recognized as such for the purposes of linking to BibDesk.

The best approach is to have your files generally find the real main file even if they are not included in the compiled version. But you can also force a syntax package to be loaded:

let g:vimtex_syntax_packages = {
      \ 'biblatex_chicago': {'load': 2},
      \}

See :help vimtex_syntax_packages.

@alexandreroberts
Copy link
Author

Also, I'm curious, I would want to only show "Open in BibDesk" if BibDesk is available. For Zotero, I did this with if executable('zotero'), so, what is the executable name for bibdesk on mac? I.e., if you open a terminal, how do you start bibdesk?

I'm not sure what the executable is called. I have played around and searched on the internet but have been unable to figure out how to open BibDesk from the terminal. There must be one. Is there a simple way to search for it on my own computer?

As for everything else: thank you, thank you! The TeX root solution solves all these little issues at once, and the vimscript you provided lets me jump straight to a BibDesk entry from my document. What a great improvement!

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

As for everything else: thank you, thank you! The TeX root solution solves all these little issues at once, and the vimscript you provided lets me jump straight to a BibDesk entry from my document. What a great improvement!

Glad to help, and glad to hear that things work for you now!

Also, I'm curious, I would want to only show "Open in BibDesk" if BibDesk is available. For Zotero, I did this with if executable('zotero'), so, what is the executable name for bibdesk on mac? I.e., if you open a terminal, how do you start bibdesk?

I'm not sure what the executable is called. I have played around and searched on the internet but have been unable to figure out how to open BibDesk from the terminal. There must be one. Is there a simple way to search for it on my own computer?

The thing is, I don't know how these things work on MacOS. It doesn't work quite like it does on Linux. Perhaps @clason would be able and willing to help out here?

@alexandreroberts
Copy link
Author

alexandreroberts commented Apr 29, 2024

A quick follow up about the citekey-to-BibDesk functionality you have already implemented: I have stumbled across what I think is a bug, arising from a citekey that has perhaps too many different punctuation marks in it.

\cite{kraus1942jabir} 
\cite{philoponos:arist.gen.corr.1.6-2.4:williams2001}

The first of these citekeys works no problem (with both the extra vimscript you provided and with the context menu approach). The second of the citekeys (philoponos:arist.gen.corr.1.6-2.4:williams2001) works with neither approach (with the context menu approach, it pops up and shows the correct citekey, but then when I select BibDesk, nothing happens).

Here's what the two citekeys look like, both properly highlighted:

Screenshot 2024-04-29 at 9 12 22 AM

Here is the context menu that pops up with the second one:

Screenshot 2024-04-29 at 9 14 43 AM

@alexandreroberts
Copy link
Author

It occurs to me that this "bug" might be related to the similar issue that arose when you were implementing the same functionality in wiki.vim. I think the solution there was to escape the colons in the URL.

@clason
Copy link
Contributor

clason commented Apr 29, 2024

I don't know any other way than the osascript mess that is used for Skim, e.g.,

function! s:viewer._check() dict abort " {{{1
let l:output = vimtex#jobs#capture(
\ 'osascript -l JavaScript -e ''Application("Skim").id()''')
if join(l:output) !~# 'net.sourceforge.skim-app'
call vimtex#log#error('Skim is not installed!')
return v:false
endif
return v:true
endfunction
.

The possible commands are not listed on a webpage but can be found through the Script Editor as explained here: https://bibdesk.sourceforge.io/manual/BibDeskHelp_80.html#SEC144

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

I have stumbled across what I think is a bug, arising from a citekey that has perhaps too many different punctuation marks in it.

\cite{kraus1942jabir} 
\cite{philoponos:arist.gen.corr.1.6-2.4:williams2001}

The second of the citekeys (philoponos:arist.gen.corr.1.6-2.4:williams2001) works with neither approach (with the context menu approach, it pops up and shows the correct citekey, but then when I select BibDesk, nothing happens).

Here is the context menu that pops up with the second one:
Screenshot 2024-04-29 at 9 14 43 AM

Well, it sure looks like the context menu picks up the correct key. On my end, the script I provided you also seems to work - but I can't really check since I don't have bibdesk. But I do see that the final url becomes x-bdsk://philoponos:arist.gen.corr.1.6-2.4:williams2001. Does that mean that the command open x-bdsk://philoponos:arist.gen.corr.1.6-2.4:williams2001 does not work from a terminal?

It occurs to me that this "bug" might be related to the similar issue that arose when you were implementing the same functionality in wiki.vim. I think the solution there was to escape the colons in the URL.

Ah, yes, that seems like it could solve this. Since you already have wiki.vim, it should be relatively easy to test. In the earlier proposed script, change:

    -call vimtex#util#www('x-bdsk://' .. l:selected)
    +call vimtex#util#www('x-bdsk://' .. wiki#url#utils#encode(l:selected))

If that works, then I might include this encode function into VimTeX.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

@clason

Thanks! That's annoying and hard to work with. @alexandreroberts, could you try to run something like this:

osascript -l JavaScript -e 'Application("BibDesk").id()'
osascript -l JavaScript -e 'Application("bibdesk").id()'

and report the output?

@alexandreroberts
Copy link
Author

I tried the change you made, but I got the error message that the function wiki#url#utils#encode is unknown:

Screenshot 2024-04-29 at 2 23 01 PM

Is there something I have to do to make this wiki function available to vimtex?


Ah, now I realized that there may have been a typo in the function name you gave me, because I have found by searching my configuration that there is a similarly-named function called wiki#url#utils#url_encode. I changed it to that, and it sort of works but then in BibDesk I get this error message:

Screenshot 2024-04-29 at 2 26 25 PM

So it seems that the URL encoding being used needs to be adjusted to whatever it was you did in the wiki case.

@alexandreroberts
Copy link
Author

I think somehow the file path and name are being inserted into the link. I don't know why. This is because the file I have open in which I tested this is at sections/a-0-0-AristNeoplat.tex.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Ah, now I realized that there may have been a typo in the function name you gave me, because I have found by searching my configuration that there is a similarly-named function called wiki#url#utils#url_encode.

Yes, sorry, my mistake.

I changed it to that, and it sort of works but then in BibDesk I get this error message:

Huh. That' strange. The url encoding should now be exactly the same as in the wiki.vim case, but the error message seems to report something else.

Can you change the call vimtex#util#www to unsilent echo instead?

@alexandreroberts
Copy link
Author

alexandreroberts commented Apr 29, 2024

Can you change the call vimtex#util#www to unsilent echo instead?

I've done that, and very strangely, it produces the exact link that we need:

Screenshot 2024-04-29 at 2 37 17 PM

Furthermore, when I command-click it (in iTerm2, this follows the link), it opens the correct bib entry in BibDesk. So I don't know why it doesn't work otherwise.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

What happens if you do open ... with that link from a terminal?

@alexandreroberts
Copy link
Author

Thanks! That's annoying and hard to work with. @alexandreroberts, could you try to run something like this:

osascript -l JavaScript -e 'Application("BibDesk").id()'
osascript -l JavaScript -e 'Application("bibdesk").id()'

and report the output?

I've run those two commands, and this is the output:

edu.ucsd.cs.mmccrack.bibdesk
edu.ucsd.cs.mmccrack.bibdesk

@alexandreroberts
Copy link
Author

What happens if you do open ... with that link from a terminal?

When I do open x-bdsk://philoponos%3Aarist.gen.corr.1.6-2.4%3Awilliams2001, it simply works: it opens the correct bib entry in BibDesk. It seems that call vimtex#util#www must do something unexpected.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Strange. It really shouldn't do anything strange. It is here:

function! vimtex#util#www(url) abort " {{{1
let l:cmd = get(#{
\ linux: '!xdg-open %s &',
\ mac: '!open %s &',
\ win: '!start %s',
\}, vimtex#util#get_os())
silent execute printf(l:cmd, a:url)
endfunction

Perhaps you could try to add an unsilent echo printf(l:cmd, a:url) above the silent execute line? Just to verify that it indeed does what we expect?

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

I've run those two commands, and this is the output:

edu.ucsd.cs.mmccrack.bibdesk
edu.ucsd.cs.mmccrack.bibdesk

Thanks! I've tried to add the guard now. Please update, then check if you still
get the BibDesk context menu option.

@alexandreroberts
Copy link
Author

Perhaps you could try to add an unsilent echo printf(l:cmd, a:url) above the silent execute line? Just to verify that it indeed does what we expect?

I've done that. This is the result when I run the command on the same citekey:

Screenshot 2024-04-29 at 2 58 36 PM

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Ok. Next, what happens if you run that command manually?

@alexandreroberts
Copy link
Author

When I run that command manually, it works.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

And it does not work if you run it from the function?

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Now, that is strange and does not really make any sense to me.

@alexandreroberts
Copy link
Author

That's right, it's still giving me:

Screenshot 2024-04-29 at 3 03 38 PM

@alexandreroberts
Copy link
Author

In case I somehow garbled your script when I pasted it into my vim config, here is what it says (pasted into here directly from my vim config):

function! OpenInBibDesk() abort
  let l:cmd_re = '\v%(%(\a*cite|Cite)\a*|bibentry|%(text|block|%(for|hy)\w+)cquote)'
  let l:cmd = vimtex#cmd#get_current()
  if empty(l:cmd)
        \ || l:cmd.name[1:] !~# l:cmd_re
        \ || len(l:cmd.args) < 1
        \ || len(l:cmd.args) > 2
    return
  endif

  let l:text = l:cmd.args[0].text
  if len(l:cmd.args) == 2
    let l:text .= ',' .. l:cmd.args[1].text
  endif
  let l:cites = split(l:text, ',\s*')

  let l:word = expand('<cword>')
  if index(l:cites, l:word) >= 0
    let l:selected = l:word
  else
    let l:selected = l:cites[0]
  endif

  if !empty(l:selected)
    call vimtex#util#www('x-bdsk://' .. wiki#url#utils#url_encode(l:selected))
  endif
endfunction

nnoremap <leader>df :call OpenInBibDesk()<cr>

@alexandreroberts
Copy link
Author

Could it be that l:selected has somehow ended up including the file path/name?

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

No, because then you should see that in #2908 (comment).

@alexandreroberts
Copy link
Author

Very strange, especially since this problem didn't come up at all in the wiki.vim case.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Could you try to do this:

vimtex#jobs#start('open x-bdsk://' .. wiki#url#utils#url_encode(l:selected))

I'm not sure if it will help, but it could.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Oh. Now I get it!

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

The thing is, doing :!... is special. See :help :!. Things like % will be replaced, which is exactly what we are seeing. So, the url encoding is generally not very compatible with :!. I'll push an update where I use system() or vimtex#jobs#start instead, as I think those should be more robust in this case, anyway.

@alexandreroberts
Copy link
Author

alexandreroberts commented Apr 29, 2024 via email

@alexandreroberts
Copy link
Author

I've run those two commands, and this is the output:

edu.ucsd.cs.mmccrack.bibdesk
edu.ucsd.cs.mmccrack.bibdesk

Thanks! I've tried to add the guard now. Please update, then check if you still get the BibDesk context menu option.

After updating, I still get BibDesk in the context menu, so it seems to have worked.

lervag added a commit that referenced this issue Apr 29, 2024
@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Great, thanks for checking.

I've pushed an update. I think most things should work now. Please test.

lervag added a commit that referenced this issue Apr 29, 2024
@lervag
Copy link
Owner

lervag commented Apr 29, 2024

I've also added url_encode to vimtex and made the bibdesk thing use it.

With that, I think we can be ready to close this issue?

Final version of the script:

function! OpenInBibDesk() abort
  let l:cmd_re = '\v%(%(\a*cite|Cite)\a*|bibentry|%(text|block|%(for|hy)\w+)cquote)'
  let l:cmd = vimtex#cmd#get_current()
  if empty(l:cmd)
        \ || l:cmd.name[1:] !~# l:cmd_re
        \ || len(l:cmd.args) < 1
        \ || len(l:cmd.args) > 2
    return
  endif

  let l:text = l:cmd.args[0].text
  if len(l:cmd.args) == 2
    let l:text .= ',' .. l:cmd.args[1].text
  endif
  let l:cites = split(l:text, ',\s*')

  let l:word = expand('<cword>')
  if index(l:cites, l:word) >= 0
    let l:selected = l:word
  else
    let l:selected = l:cites[0]
  endif

  if !empty(l:selected)
    call vimtex#util#www('x-bdsk://' .. vimtex#util#url_encode(l:selected))
  endif
endfunction

@alexandreroberts
Copy link
Author

Great, thanks for checking.

I've pushed an update. I think most things should work now. Please test.

It works! Now when I use the shortcut command on that colon-laden citekey, it jumps right to the correct entry in BibDesk. Thank you!

I think it would be great for this vimscript to be incorporated into Vimtex, perhaps with an additional option that defaults to off so that it doesn't bog down configurations of people who are not using BibDesk.

@alexandreroberts
Copy link
Author

Ah, great, I will change the script in my config -- or have you added the OpenInBibDesk script to Vimtex itself?

@alexandreroberts
Copy link
Author

Just checked: I see that OpenInBibDesk is not yet part of Vimtex. That's fine for me, but as I said, perhaps you might consider adding it in the future.

Thanks again, and yes, I think you can close this now.

lervag added a commit that referenced this issue Apr 29, 2024
@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Just checked: I see that OpenInBibDesk is not yet part of Vimtex. That's fine for me, but as I said, perhaps you might consider adding it in the future.

Nah, I don't quite see how fit it in properly. However, I did something else that I think makes more sense. If you update again, then you can change your custom script to this:

function! OpenInBibDesk() abort
  let l:key = vimtex#cite#get_key()
  if empty(l:key) | return | endif

  call vimtex#util#www('x-bdsk://' .. vimtex#util#url_encode(l:key))
endfunction

I'll also add a short doc for the vimtex#cite#get_key function.

Thanks again, and yes, I think you can close this now.

Great, I'm closing it now.

@lervag lervag closed this as completed Apr 29, 2024
@alexandreroberts
Copy link
Author

Thanks so much! This concise version of the function works beautifully. This is such a wonderful new feature of Vimtex, thank you for taking the time to implement it.

@lervag
Copy link
Owner

lervag commented Apr 29, 2024

Thanks so much! This concise version of the function works beautifully. This is such a wonderful new feature of Vimtex, thank you for taking the time to implement it.

Thanks for the kind words! And thanks for providing the ideas that help make VimTeX better!

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

No branches or pull requests

3 participants