#= Functions to manage the library =# using JSON, StringDistances """ Add `entry` to `bibliography` on key `id` Defines `pre_add_to_bib` and `after_add_to_bib`. """ function addtobibliography!(bibliography::Bibliography, id::String, entry::Citation) @hook :pre_add_to_bib exists = id in keys(bibliography) info("The id you are adding $(id) does " * (exists ? "" : "not ") * "exists") if exists oldentry = bibliography[id] # TODO: run a Levenshtein distance on the two entry and decide # what to do Options should be to merge/replace or keep both. # In the latter the id must be modified (like id-$counter) old = lowercase(get(oldentry,"title","")) new = lowercase(get(entry,"title","-")) differencepercent = compare(TokenMax(RatcliffObershelp()), old, new) if differencepercent > 0.8 @hook :duplicated_paper warn("The old and the new seems to be the same paper (similarity is $(differencepercent))") @show json(oldentry) @show json(entry) else @hook :similar_paper info("keeping both") id = nextidnumber(bibliography,id) end end bibliography[id] = entry @hook :after_add_to_bib end """ Set `newbib` as a the bibliography, replacing `bibliography`. """ function setbibliography!(bibliography::Bibliography, newbib::Bibliography) empty!(bibliography) merge!(bibliography, newbib) end import Base.pop! function pop!(bibliography::Bibliography, key::String) copy = Dict(bibliography) p = Base.pop!(copy, key) # FIXME: remove this Base. empty!(bibliography) foreach(k -> bibliography[k] = copy[k], keys(copy)) # Behaves like a real `pop`, returning the popped key value p end # FIXME: find files? """Add all entries in a bibtex string to the current bibliography""" function addbibtex!(bibliography, bibstring) bibs = Bibliography(bibstring) foreach(bib -> addtobibliography!(bibliography, createcitekey(bibs[bib]), bibs[bib]), keys(bibs)) "ok" end function splitauthors(bib::Citation) authors = split(bib["author"], " and ") map(a -> (split(strip(a, ['}', '{']), ", ")), authors) end """Create the cite key given a bibtex object""" function createcitekey(bib::Citation) authors = splitauthors(bib) firstauthor = length(authors) > 0 ? authors[1][1] : "Unnamed" title = split(get(bib, "title", "Untitled"), " ")[1] year = match(r"([0-9]{4})", get(bib, "year", get(bib, "date", "0000")))[1] string(firstauthor, "_", title, "_", year) |> lowercase end """Generates a new id, with the same key, but with a number at the end (id-\$number) so that it is unique in the library. Fallback for duplicates. """ function nextidnumber(bibliography::Bibliography,id::String) num = 0 while true nid = string(id, "-", num) nid in keys(bibliography) || break num += 1 end nid end # """ # Apply some cleaning to the bibtex citation, namely fixing the key id. # Useful when adding a bibtex directly to verify that it conforms to our "standard" # """ # function cleancitation(cit) # end