[WIP] add folding for bib files#2066
[WIP] add folding for bib files#2066yongrenjie wants to merge 11 commits intolervag:masterfrom yongrenjie:2065-bib-foldtext
Conversation
|
Great, thanks! I'll review as soon as I get the chance. One thing I notice immediately: Should we shorten the first part of the foldtext if it becomes too long, e.g. in the lines |
|
That's something I was not entirely sure about, too. On one hand it would looks nicer if it's trimmed. On the other hand I think the cite key is the most important bit of info. In this case, if we trim the length to 32 or fewer chars, then the user can't differentiate the keys I experimented a bit with calculating the length of the longest key when opening the buffer, and setting it to a |
|
I pushed a second commit which does this, it's just a draft to see what you think about the behaviour, which I can clean up later! Here's a short video I recorded. The buffer variable is recalculated when opening and also when saving, hence the 'jumps' when I save: Untitled.mp4 |
Yes, agreed. Good point.
Yes, that sounds good. I think having an option as well, e.g.
So, in the insane case you have ~10000 lines, it would still only be about ~250 ms, which should be acceptable for most people. Let's say they have a slow computer, then it could be as bad as 1 second. Still acceptable if this is only when the file is initially opened. |
lervag
left a comment
There was a problem hiding this comment.
I did a review of the code as well, and I am very glad to see that this is high quality content! Well done!
One "major" discussion point: should we somehow merge some of the bulk code here with the code under autoload/vimtex/parser/bib.vim? That could help make it useful for other related features in the future. Note, I won't block merging because of this, I can also simply consider to do that myself at some time. But hearing other peoples opinions are always interesting.
|
I must admit I've not looked at the bib parsing code much, and I'm going to be a little busy these few days, but will come back to it (and make the changes above) when I can! As for moving the code inside If we modify
That would introduce some kind of asymmetry between the bibtex/bibparse and vim parsers, which seems to be a bit unsatisfying to me. The alternative would be to keep the parsing function separate, lets say write a All in all I'm more inclined to keep it separate, mainly because I don't see the best way to merge the code, but I would defer to you on that 🙂 One benefit of utilising the existing parser (if it's feasible, and not as hard as I've claimed) might be to deal with edge cases. I tried to deal with a reasonable number of cases, but I know the foldtext function will break with pathological input like On the topic of edge cases: is it worth adding some tests for the above as well? |
No problem, and no rush!
Let's first assume we don't need to care about the performance. In this case, I think the only real change would be to allow a list of lines as an alternative input. It would bring an asymmetry, unless we also update the other alternatives to work with this kind of input (e.g. we could save the lines to a file first).
If performance is important (and it may very well be!), then I think the idea would be to implement the parser as a full API function with signature I do agree that adding such an extra function does seem slightly "off", but I think this is one of those cases where some comments may help our future selves (and others) understand the reasons we decided this (or that) way.
Yes, definitely! I think it could be quite simple, actually:
I think the |
|
By the way; I realize there's a choice here that is undecided and sort of hard to decide. My suggestion would be to go for the cheap parser, but to move the main parsing code to e.g. |
|
Ok, finally free from real life work for a bit 😅 I agree with your assessment re. implementing |
|
I think the actual code is done. Here is how it looks with the default and with I added some docs as well, and will look into tests. But one more thing regarding edge cases: I'm pretty certain that the most brittle part of the current setup is actually @string{ foo = "Mrs. Foo" }
@article{Kupce2017ACIE,
doi = {10.1002/anie.201705506},
author = {Kup{\v{c}}e, {\=E}riks and Claridge, Tim D.\ W.},
journal = {Angew.\ Chem.\ Int.\ Ed.},
title = {{NOAH}: {NMR} Supersequences for Small Molecule Analysis and Structure Elucidation},
year = {2017},
volume = {56},
issue = {39},
pages = {11779--11783},
}produces a single fold for all 12 lines, instead of (probably) the more natural result of |
Great, this looks good! One possibly good idea could be to parse the titlestring and remove the brackets, as that would allow to show more of the title text. But that's clearly not very important, of course.
Great!
Ah, yes. I've generally found |
lervag
left a comment
There was a problem hiding this comment.
I understand you still want to make some more changes. Still, here are some minor comments to the current version. In general, I'm very happy to see that you are suggesting very high quality work (in my opinion!). Thanks!
|
@lervag Sorry about all the force pushes/rebasing! I think I'm done for now, though. I wrote a foldexpr in
Here With the current code in the PR, There are also some tests now, and I changed whatever was necessary in the docs (which turned out to be very little). Let me know what you think / if you want me to change anything, whenever you are free, of course! |
|
Thanks! And sorry for the delay, I'll try and get time to review and possibly merge tomorrow or the day after! |
lervag
left a comment
There was a problem hiding this comment.
@lervag Sorry about all the force pushes/rebasing! I think I'm done for now, though.
No need to apologize; I really do prefer the force pushing (although I don't enforce it). :)
I wrote a foldexpr in
vimtex#fold#bib#level(lnum)which seems to be fairly robust towards badly positioned curly braces (the test contains a pretty good demonstration IMO). It's slow, no surprises I guess!
Yes, it's a known "issue" with foldexpr and the reason why plugins like Fastfold exists. Thanks for looking into the timings. I could make the same tests on my machine, but your bib file seems to be unavailable (perhaps private?).
With the current code in the PR,
hsqc8.bibtakes 855 ms to startup (this includes various other plugins which I didn't bother disabling), whereas if I revert tofoldmethod=syntax(but keeping the foldtext functions) this drops to 446 ms. So I wonder whether one option to 'fall back' tofoldmethod=syntax, but keep the foldtext functionality, might be useful. Or maybe I'm just worrying too much about people who keep crazy 10k-line bib files. :-)
I won't mind bothering users a little bit with pushing this and then waiting for the reactions. I'll have a deeper look into the foldexpr function after merging to see if I can spot some optimizations (I did not see anything obvious, except perhaps a minor improvement with the foldlevel() thing.
There are also some tests now, and I changed whatever was necessary in the docs (which turned out to be very little).
Great!
Let me know what you think / if you want me to change anything, whenever you are free, of course!
I had a few minor comments/suggestions. After that, I think I'll do a merge. Again, I appreciate the high quality of your contribution!
Whoops! Yes it was private. Fixed now. https://github.com/yongrenjie/hsqc-paper/blob/master/main_final/hsqc.bib I'll refactor the rest tomorrow probably. Had another look at the foldexpr and managed to squeeze out a 5–10% speedup (so now [I'm sure there is some way to improve it, though; the alternative is claiming that I got it right on the first go. :)] |
... The actual parsing is now done in vimtex#parser#bib#cheap_parse(), and the folding functions merely make use of this.
This makes foldtext look sensible in the very specific case where one opens a blank bib file, adds an entry to it, and closes the fold before saving.
|
@lervag OK, I'm finally done! I couldn't get around recursively calling Basically the last two commits contain the only 'new' changes since your last round of comments. I also added more tests, which got squashed into the earlier tests commit. |
|
Thanks! It looks good! I've looked at the foldlevel code: You need the recursion because you want to handle the case of single line entries. I'm curious if it would not be a better idea to handle single line entries by not giving them the result |
|
I've merged now. I also made some minor changes on top. Nothing important. To test my idea, I believe the only necessary change is to add to the " Check if we're at fold start
let l:text = join(getline(l:firstline, a:lnum))
let l:braces_balanced = s:count(l:text, '{') == s:count(l:text, '}')
if l:firstline == a:lnum
return l:braces_balanced ? 0 : '>1'
endif
" Beginning of entry wasn't found
if l:firstline == 0 | return 0 | endif
" Check if braces are closed by the current line
return l:braces_balanced ? '<1' : 1Ref: vimtex/autoload/vimtex/fold/bib.vim Lines 48 to 57 in 1782e47 |
|
Thanks! I have a vague recollection that I tried this, and it failed the tests. IIRC the problematic bib entry is vimtex/test/test-folding-bib/test.bib Lines 62 to 73 in 1782e47 Admittedly, it is probably a pretty rare edge case, so if there is a performance boost it might be worthwhile on balance to change it. |
(It's now in vimtex itself(!!) see lervag/vimtex#2066.)
|
I believe I've managed to simplify and improve a little bit. I've pushed an update now; could you test the timings again on your end and see if it has improved? Could you share the process you use for doing the timings? |
|
I've looked at the numbers on my side, and I don't really see any significant speedup on my latest changes. But at least the code is somewhat shorter. For more detailed profiling, one can use this: " test.vim
set nocompatible
let &rtp = '../../..,' . &rtp
filetype plugin on
let g:vimtex_fold_bib_enabled = 1
function! TestProfile() abort
call vimtex#profile#start()
normal! zM
call vimtex#profile#stop()
endfunction
autocmd BufEnter * call TestProfile()The It seems the most expensive lines are these: (From the current version of the code, so not quite what you proposed, but it is generally the same code.) |
|
Oh, my 'profiling' is very crude, it's just a function! TimeBibFold() abort
let start_time = reltime()
call vimtex#fold#bib#init()
echomsg 'initialised in time' . reltimestr(reltime(start_time))
let start_time = reltime()
call map(range(1, line('$')), 'foldlevel(v:val)')
echomsg 'foldexprs calculated in' . reltimestr(reltime(start_time))
endfunctionBy appropriately inserting The timings are pretty much the same as before, which is a good thing, because I think you made it easier to read. When I wrote this I think I tried to shortcircuit as much as possible, but chances are in 'typical' cases there's not all that much difference. |
Thanks! Simple solutions are good, especially when they're sufficient :) And I agree, the idea of using Let's consider this matter resolved for now, then. Again, thanks for your contribution! |
|
Hi! I believe the recent commit (related to this PR), now folds bib files by default. Is there any way to avoid this? (I personally prefer no folds in bib files). |
|
Oh, yeah, folding should remain opt-in ;) |
|
I assumed that this was conditional on folding enabled -- if I had realized that this was a new, independent, folding option to be turned on by default, I would have spoken up, loudly ;) |
I agree with @clason. Such options should be opt-in. |
|
OK, you can use the option first, and I'll put something together, is that OK? |
|
To be clear, I am completely fine with it being enabled by default (or even automatically; I don't care :P) if general folding is enabled. But if folding is disabled, it must be disabled too. |
|
Thanks, @paniash; I agree that it was wrong to make the new bib folds enabled by default. It is changed now through the PR by @yongrenjie in #2089. Thanks for pitching in, @clason. I'm curious, what do you mean with "general folding is enabled"? Do you mean e.g. if |
|
Yes, |


Since opening the issue (#2065) I've tweaked the output a bit, here's a sample (first one unfolded for comparison):