Skip to content

Commit

Permalink
refactor: split caches, make API key-focused
Browse files Browse the repository at this point in the history
Sorry for this breaking change, but I wanted to get the foundations
right before tagging 1.0.

This completely restructures the core of citar to borrow some code and
ideas from the org-mode oc-basic package.

In particular, it changes to using two primary caches:

- bibliography
- completion

Both of these now use hash tables, rather than lists.

Caching functionality is also changed, and the API now focuses on
citekeys as arguments for key functions.

Finally, citar--parse-bibliography should re-parse bibliography files
upon change.

Fix emacs-citar#623 Close emacs-citar#627
  • Loading branch information
bdarcus authored and roshanshariff committed Jun 19, 2022
1 parent fee49a8 commit bdbd046
Show file tree
Hide file tree
Showing 3 changed files with 298 additions and 356 deletions.
45 changes: 31 additions & 14 deletions CONTRIBUTING.org
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,49 @@

If you would like to contribute, details:

- For more signifiant potential changes, file an issue first to get feedback on the basic idea.
- For more significant potential changes, file an issue first to get feedback on the basic idea.
- If you do submit a PR, follow the [[https://github.com/bbatsov/emacs-lisp-style-guide][elisp style guide]], and [[https://cbea.ms/git-commit/][these suggestions]] on git commit messages.
- For working on lists and such, we primarily use the =seq= functions, and occassionally ~dolist~.

** Basic Architecture

Citar has two primary caches, each of which store the data in hash tables:

- bibliographic :: keys are citekeys, values are alists of entry fields
- completion :: keys are completion strings, values are citekeys

The =citar--ref-completion-table= function returns a hash table from the bibliographic cache, and ~citar--get-entry~ and ~-citar--get-value~ provide access to those data.
Most user-accessible citar functions take an argument ~key~ or ~keys~.
Some functions also take an ~entry~ argument, and ~citar--get-value~ takes either.
When using these functions, you should keep in mind that unless you pass an entry alist to ~citar--get-value~, and instead use a key, each call to that function will query the cache.
This, therefore, is a better pattern to use:

#+begin_src emacs-lisp

(let* ((entry (citar--get-entry key))
(title (citar--get-value entry "title")))
(message title))

#+end_src


** Extending citar

Most user-accessible citar functions take an argument ~key-entry~ or ~keys-entries~.
These expect, respectively, a cons cell of a citation key (a string like "SmithWritingHistory1987") and the corresponding bibliography entry for that citation, or a list of such cons cells.
If you wish to extend citar at the user-action level, perhaps by adding a function to one of the embark keymaps, you will find it easiest to reproduce this pattern.
If you need to build the cons cells manually, this can be accomplished via ~citar--get-entry~.
So, for example, to insert the annotations from a pdf into a buffer, the following pair of functions might be used:
You can use ~citar-select-ref~ or ~citar-select-refs~ to write custom commands.
An example:

#+begin_src emacs-lisp


(defun my/citar-insert-annots (keys-entries)
(defun my/citar-insert-annots (keys)
"insert annotations as org text from KEYS-ENTRIES"
(interactive (list (citar-select-refs
:rebuild-cache current-prefix-arg)))
(interactive (list (citar-select-refs)))
(let* ((files
(seq-mapcat (lambda (key-entry)
(seq-mapcat (lambda (key)
(citar-file--files-for-entry
(car key-entry) (cdr key-entry)
key (citar--get-entry key)
'("/") '("pdf")))
keys-entries ))
keys ))
(output (seq-map
(lambda (file)
(pdf-annot-markups-as-org-text ;; you'll still need to write this function!
Expand All @@ -44,8 +62,7 @@ So, for example, to insert the annotations from a pdf into a buffer, the followi

(defun my/independent-insert-annots (key)
"helper function to insert annotations without the bibtex-actins apparatus"
(let ((key-entry (cons key (citar--get-entry key))))
(my/citar-insert-annots (list key-entry))))
(my/citar-insert-annots (list key)))


#+end_src
Expand Down
37 changes: 9 additions & 28 deletions citar-file.el
Original file line number Diff line number Diff line change
Expand Up @@ -233,31 +233,6 @@ need to scan the contents of DIRS in this case."
(puthash key (nreverse filelist) files))
files))))

(defun citar-file--has-file-notes-hash ()
"Return a hash of keys and file paths for notes."
(citar-file--directory-files
citar-notes-paths nil citar-file-note-extensions
citar-file-additional-files-separator))

(defun citar-file--has-library-files-hash ()
"Return a hash of keys and file paths for library files."
(citar-file--directory-files
citar-library-paths nil citar-library-file-extensions
citar-file-additional-files-separator))

(defun citar-file--keys-with-file-notes ()
"Return a list of keys with file notes."
(hash-table-keys (citar-file--has-file-notes-hash)))

(defun citar-file--keys-with-library-files ()
"Return a list of keys with file notes."
(hash-table-keys (citar-file--has-library-files-hash)))

(defun citar-file-has-notes ()
"Return a predicate testing whether a reference has associated notes."
(citar-file--has-file citar-notes-paths
citar-file-note-extensions))

(defun citar-file--has-file (dirs extensions &optional entry-field)
"Return predicate testing whether a key and entry have associated files.
Expand All @@ -277,8 +252,9 @@ once per command; the function it returns can be called
repeatedly."
(let ((files (citar-file--directory-files dirs nil extensions
citar-file-additional-files-separator)))
(lambda (key entry)
(let* ((xref (citar--get-value "crossref" entry))
(lambda (key &optional entry)
(let* ((nentry (or entry (citar--get-entry key)))
(xref (citar--get-value "crossref" nentry))
(cached (if (and xref
(not (eq 'unknown (gethash xref files 'unknown))))
(gethash xref files 'unknown)
Expand All @@ -292,7 +268,7 @@ repeatedly."
(puthash key
(seq-some
#'file-exists-p
(citar-file--parse-file-field entry entry-field dirs extensions))
(citar-file--parse-file-field nentry entry-field dirs extensions))
files))))))

(defun citar-file--files-for-entry (key entry dirs extensions)
Expand Down Expand Up @@ -351,6 +327,11 @@ of files found in two ways:
nil 0 nil
file)))

(defun citar-file-has-notes ()
"Return a predicate testing whether a reference has associated notes."
(citar-file--has-file citar-notes-paths
citar-file-note-extensions))

(defun citar-file--open-note (key entry)
"Open a note file from KEY and ENTRY."
(if-let* ((file (citar-file--get-note-filename key
Expand Down
Loading

0 comments on commit bdbd046

Please sign in to comment.