X-Git-Url: https://git.donarmstrong.com/?p=org-ref.git;a=blobdiff_plain;f=org-ref.org;h=1f66c11842d017843aa391a27cc66e13bc4debc8;hp=334be1382acf102f949ce2d405b5c122e0268c25;hb=f60345ce8373124a6718dfa963b598650dfbb656;hpb=6dc413f2df948835cd041f52f1ca9327ac188a67 diff --git a/org-ref.org b/org-ref.org index 334be13..1f66c11 100644 --- a/org-ref.org +++ b/org-ref.org @@ -38,11 +38,11 @@ This document is an experiment at creating a literate program to provide similar ;;; Commentary: ;; -;; Lisp code to setup bibliography cite, ref and label org-mode links. -;; also sets up reftex for org-mode. The links are clickable and do -;; things that are useful. You should really read org-ref.org for details. +;; Lisp code to setup bibliography cite, ref and label org-mode links. also +;; sets up reftex and helm for org-mode citations. The links are clickable and +;; do things that are useful. You should really read org-ref.org for details. ;; -;; Package-Requires: ((dash)) +;; Package-Requires: ((dash) (helm) (helm-bibtex)) #+END_SRC ** requires @@ -51,6 +51,8 @@ The only external require is reftex-cite #+BEGIN_SRC emacs-lisp :tangle org-ref.el (require 'reftex-cite) (require 'dash) +(require 'helm) +(require 'helm-bibtex) #+END_SRC ** Custom variables @@ -113,13 +115,36 @@ There are some variables needed later to tell this library where you store your ;;(org-tree-to-indirect-buffer) (outline-previous-visible-heading 1) (recenter-top-bottom 0)) - "User-defined way to open a notes entry. This is excecuted after the entry is found, with the cursor at the beginning of the headline. The default setting fully expands the notes, and moves the headline to the top of the buffer") + "User-defined way to open a notes entry. This is excecuted after the entry is found, with the cursor at the beginning of the headline. The default setting fully expands the notes, and moves the headline to the top of the buffer" +:type 'function +:group 'org-ref) (defcustom org-ref-open-pdf-function 'org-ref-open-pdf-at-point "User-defined function to open a pdf from a link. The function must get the key at point, and derive a path to the pdf file, then open it. The default function is `org-ref-open-pdf-at-point'." - :type 'function) + :type 'function + :group 'org-ref) + + +(defcustom org-ref-insert-cite-function + 'org-ref-helm-insert-cite-link + "Function to call to insert citation links. The default is `org-ref-helm-insert-cite-link' which uses `helm-bibtex'. org-ref modifies helm-bibtex a little bit to give org-mode citations, and to reorder default actions. You may use `org-ref-insert-cite-link' if you like the reftex interface." + :type 'function + :group 'org-ref) + + +(defcustom org-ref-cite-onclick-function + 'org-ref-cite-click-helm + "Function that runs when you click on a cite link. The function must take no arguments. You may also use `org-ref-cite-onclick-minibuffer-menu' if you do not like helm." + :type 'function + :group 'org-ref) + +(defcustom org-ref-show-citation-on-enter t + "If non-nil add a hook function to show the citation summary in + the minibuffer just by putting the cursor in a link" + :group 'org-ref) + #+END_SRC This next variable determines the citation types that are available in org-ref. Links for each one are automatically generated, and completion functions are automatically generated. Users may add to this list in their own init files. @@ -193,11 +218,35 @@ We setup reftex here. We use a custom insert cite link function defined here: [[ ;; I do not remember why I put this next line in. It doesn't ;; work for org-files. Nothing very bad happens, but it gives ;; an annoying error. Commenting it out for now. - ;(reftex-parse-all) + ;(reftex-parse-all ) (make-local-variable 'reftex-cite-format) - (setq reftex-cite-format 'org) - (define-key org-mode-map (kbd org-ref-insert-cite-key) 'org-ref-insert-cite-link)) + (setq reftex-cite-format 'org)) + +;; define key for inserting citations +(define-key org-mode-map + (kbd org-ref-insert-cite-key) + org-ref-insert-cite-function) + +(when org-ref-show-citation-on-enter + (setq org-ref-message-timer + (run-with-idle-timer 0.5 t 'org-ref-link-message))) + +(defun org-ref-show-link-messages () + "Turn on link messages. You will see a message in the +minibuffer when on a cite, ref or label link." + (interactive) + (setq org-ref-message-timer + (run-with-idle-timer 0.5 t 'org-ref-link-message)) + ) +(defun org-ref-cancel-link-messages () + "Stop showing messages in minibuffer when on a link." + (interactive) + (cancel-timer org-ref-message-timer)) + +;; this approach caused the selected region to not be highlighted any more. +; (add-hook 'post-command-hook 'org-ref-link-message)) +; (remove-hook 'post-command-hook 'org-ref-link-message)) (add-hook 'org-mode-hook 'org-mode-reftex-setup) @@ -550,7 +599,6 @@ We use a link for the bibliography so that we can click on it to open the biblio (let* ((bibfile) ;; object is the link you clicked on (object (org-element-context)) - (link-string-beginning) (link-string-end)) @@ -864,23 +912,30 @@ In long documents, a list of figures is not uncommon. Here we create a clickable #+END_SRC ** label -The label link provides a way to create labels in org-mode. We make it clickable because we want to make sure labels are unique. This code will tell you how many instances of a label are found. We search for label links, LaTeX labels, and the org-mode format for labels. We probably should search for tblnames too. -*************** TODO search tblnames, custom_ids and check for case sensitivity -*************** END +The label link provides a way to create labels in org-mode. We make it clickable because we want to make sure labels are unique. This code will tell you how many instances of a label are found. We search for label links, LaTeX labels, and org-mode format for labels, tblnames too. #+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref-count-labels (label) + "Counts number of matches for label in the document" + (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max) t) + ;; for tblname, it is not enough to get word boundary + ;; tab-little and tab-little-2 match then. + (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t) + (count-matches (format "\\label{%s}\\b" label) (point-min) (point-max) t) + ;; this is the org-format #+label: + (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t) + (let ((custom-id-count 0)) + (org-map-entries + (lambda () + (when (string= label (org-entry-get (point) "CUSTOM_ID")) + (setq custom-id-count (+ 1 custom-id-count))))) + custom-id-count))) + (org-add-link-type "label" (lambda (label) "on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels!" - (message (format "%s occurences" - (+ (count-matches (format "label:%s\\b[^-:]" label) (point-min) (point-max) t) - ;; for tblname, it is not enough to get word boundary - ;; tab-little and tab-little-2 match then. - (count-matches (format "^#\\+tblname:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t) - (count-matches (format "\\label{%s}\\b" label) (point-min) (point-max) t) - ;; this is the org-format #+label: - (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max) t))))) + (message (format "%s occurences" (org-ref-count-labels label)))) (lambda (keyword desc format) (cond ((eq format 'html) (format "()" path)) @@ -1044,6 +1099,29 @@ Now, we can put all the labels together which will give us a list of candidates. (append matches (org-ref-get-org-labels) (org-ref-get-latex-labels) (org-ref-get-tblnames) (org-ref-get-custom-ids)))))) #+END_SRC +Let us make a helm function to insert a label link. This will help you enter unique labels. +#+BEGIN_SRC emacs-lisp +(defun org-ref-helm-insert-label-link () + "Insert a label link. helm just shows you what labels already exist." + (interactive) + (let* ((labels (org-ref-get-labels)) + (cb (current-buffer))) + (helm :sources `(((name . "Existing labels") + (candidates . ,labels) + (action . (lambda (label) + ;; unfortunately I do not have markers here + (org-open-link-from-string (format "ref:%s" label))))) + ((name . "Create new label") + (dummy) + (action . (lambda (label) + (switch-to-buffer ,cb) + (insert + (concat + "label:" + (or label + helm-pattern)))))))))) +#+END_SRC + Now we create the completion function. This works from the org-machinery, e.g. if you type C-c C-l to insert a link, and use completion by pressing tab. #+BEGIN_SRC emacs-lisp :tangle org-ref.el @@ -1062,6 +1140,44 @@ Alternatively, you may want to just call a function that inserts a link with com (insert (org-ref-complete-link))) #+END_SRC +Another alternative ref insertion is to use helm. + +#+BEGIN_SRC emacs-lisp +(defun org-ref-helm-insert-ref-link () + "Helm menu to insert ref links to labels in the document. +Use C-u to insert a different kind of ref link." + (interactive) + (let* ((labels (org-ref-get-labels)) + (contexts (mapcar 'org-ref-get-label-context labels)) + (cb (current-buffer))) + + (helm :sources `(((name . "Available labels to ref") + (candidates . ,(loop for label in labels + for context in contexts +;; we do some kludgy adding spaces and bars to make it "easier" to see in helm. + collect (cons (concat + label "\n" + (mapconcat + (lambda (x) + (concat " |" x)) + (split-string context "\n") + "\n" + ) "\n\n") label))) + (action . (lambda (label) + (switch-to-buffer ,cb) + (insert + (concat + (if helm-current-prefix-arg + (helm :sources '((name . "Ref link types") + (candidates . ("ref" "eqref" "pageref" "nameref")) + (action . (lambda (x) x)))) + "ref") + ":" label))))))))) +#+END_SRC + +#+RESULTS: +: org-ref-helm-insert-ref-link + ** pageref This refers to the page of a label in LaTeX. @@ -1465,12 +1581,13 @@ Prompt for NEW-FILE includes bib files in org-ref-default-bibliography, and bib (interactive) (let* ((results (org-ref-get-bibtex-key-and-file)) (key (car results)) - (bibfile (cdr results))) + (bibfile (cdr results)) + doi) (save-excursion (with-temp-buffer (insert-file-contents bibfile) (bibtex-search-entry key) - (bibtex-autokey-get-field "doi") + (setq doi (bibtex-autokey-get-field "doi")) ;; in case doi is a url, remove the url part. (replace-regexp-in-string "^http://dx.doi.org/" "" doi))))) @@ -1727,7 +1844,7 @@ and the completion function." (eval-expression `(org-add-link-type ,type - 'org-ref-cite-onclick-minibuffer-menu + org-ref-cite-onclick-function (quote ,(intern (format "org-ref-format-%s" type))))) ;; create the completion function @@ -1793,6 +1910,8 @@ inserted. Use a prefix arg to get a menu of citation types." (reftex-citation))) ) #+END_SRC +cite:zhou-2004-first-lda-u,paier-2006-errat,boes-2015-estim-bulk + #+RESULTS: : org-ref-insert-cite-link @@ -1991,126 +2110,13 @@ And at the end of the document put \makeglossaries. (format "\\Glspl{%s}" path))))) #+END_SRC -#+RESULTS: -| Glspl | nil | (lambda (path desc format) (cond ((eq format (quote latex)) (format \Glspl{%s} path)))) | -| Gls | nil | (lambda (path desc format) (cond ((eq format (quote latex)) (format \Gls{%s} path)))) | -| glspl | nil | (lambda (path desc format) (cond ((eq format (quote latex)) (format \glspl{%s} path)))) | -| gls | nil | (lambda (path desc format) (cond ((eq format (quote latex)) (format \gls{%s} path)))) | -| newglossaryentry | nil | (lambda (path desc format) (cond ((eq format (quote latex)) (format \newglossaryentry{%s}{%s} path desc)))) | -| google | (lambda (link-string) (browse-url (format http://www.google.com/search?q=%s (url-hexify-string link-string)))) | nil | -| ResearcherID | (lambda (link-string) (browse-url (format http://www.researcherid.com/rid/%s link-string))) | nil | -| orcid | (lambda (link-string) (browse-url (format http://orcid.org/%s link-string))) | nil | -| message | org-mac-message-open | nil | -| mac-outlook | org-mac-outlook-message-open | nil | -| skim | org-mac-skim-open | nil | -| addressbook | org-mac-addressbook-item-open | nil | -| x-together-item | org-mac-together-item-open | nil | -| ans | (lambda (path) (let* ((fields (split-string path ::)) (label (nth 0 fields)) (data (nth 1 fields)) (data-file (format %s-%s.dat tq-userid label))) (let ((temp-file data-file) (temp-buffer (get-buffer-create (generate-new-buffer-name *temp file*)))) (unwind-protect (prog1 (save-current-buffer (set-buffer temp-buffer) (insert data)) (save-current-buffer (set-buffer temp-buffer) (write-region nil nil temp-file nil 0))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))) (mygit (format git add %s data-file)) (mygit (format git commit -m "%s" data-file)) (mygit git push origin master))) | nil | -| mc | (lambda (link) (org-entry-put (point) ANSWER link) (save-restriction (save-excursion (org-narrow-to-subtree) (goto-char (point-max)) (if (bolp) nil (insert \n)) (insert (format # you chose %s link))))) | nil | -| exercise | (lambda (arg) (tq-check-internet) (tq-get-assignment arg)) | nil | -| solution | (lambda (label) (tq-check-internet) (let ((default-directory (file-name-as-directory (expand-file-name tq-root-directory)))) (if (file-exists-p solutions) nil (make-directory solutions)) (let ((default-directory (file-name-as-directory (expand-file-name solutions)))) (if (file-exists-p label) (progn (find-file (concat label / label .org)) (tq-update)) (mygit (format git clone %s@%s:solutions/%s tq-current-course tq-git-server label)) (find-file (concat label / label .org)))))) | nil | -| assignment | (lambda (arg) (tq-check-internet) (tq-get-assignment arg)) | nil | -| doi | doi-link-menu | nil | -| bibentry | org-ref-cite-onclick-minibuffer-menu | org-ref-format-bibentry | -| Autocites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Autocites | -| autocites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-autocites | -| supercites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-supercites | -| Textcites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Textcites | -| textcites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-textcites | -| Smartcites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Smartcites | -| smartcites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-smartcites | -| footcitetexts | org-ref-cite-onclick-minibuffer-menu | org-ref-format-footcitetexts | -| footcites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-footcites | -| Parencites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Parencites | -| parencites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-parencites | -| Cites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Cites | -| cites | org-ref-cite-onclick-minibuffer-menu | org-ref-format-cites | -| fnotecite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-fnotecite | -| Pnotecite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Pnotecite | -| pnotecite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-pnotecite | -| Notecite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Notecite | -| notecite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-notecite | -| footfullcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-footfullcite | -| fullcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-fullcite | -| citeurl | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citeurl | -| citedate* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citedate* | -| citedate | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citedate | -| citetitle* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citetitle* | -| citetitle | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citetitle | -| Citeauthor* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citeauthor* | -| Autocite* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Autocite* | -| autocite* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-autocite* | -| Autocite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Autocite | -| autocite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-autocite | -| supercite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-supercite | -| parencite* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-parencite* | -| cite* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-cite* | -| Smartcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Smartcite | -| smartcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-smartcite | -| Textcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Textcite | -| textcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-textcite | -| footcitetext | org-ref-cite-onclick-minibuffer-menu | org-ref-format-footcitetext | -| footcite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-footcite | -| Parencite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Parencite | -| parencite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-parencite | -| Cite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Cite | -| Citeauthor | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citeauthor | -| Citealp | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citealp | -| Citealt | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citealt | -| Citep | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citep | -| Citet | org-ref-cite-onclick-minibuffer-menu | org-ref-format-Citet | -| citeyear* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citeyear* | -| citeyear | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citeyear | -| citeauthor* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citeauthor* | -| citeauthor | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citeauthor | -| citetext | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citetext | -| citenum | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citenum | -| citealp* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citealp* | -| citealp | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citealp | -| citealt* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citealt* | -| citealt | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citealt | -| citep* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citep* | -| citep | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citep | -| citet* | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citet* | -| citet | org-ref-cite-onclick-minibuffer-menu | org-ref-format-citet | -| nocite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-nocite | -| cite | org-ref-cite-onclick-minibuffer-menu | org-ref-format-cite | -| eqref | (lambda (label) on clicking goto the label. Navigate back with C-c & (org-mark-ring-push) (widen) (goto-char (point-min)) (if (or (re-search-forward (format label:%s label) nil t) (re-search-forward (format \label{%s} label) nil t) (re-search-forward (format ^#\+label:\s-*\(%s\)\b label) nil t)) nil (org-mark-ring-goto) (error %s not found label)) (message go back with (org-mark-ring-goto) `C-c &`)) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format (%s) path)) ((eq format (quote latex)) (format \eqref{%s} keyword)))) | -| nameref | (lambda (label) on clicking goto the label. Navigate back with C-c & (org-mark-ring-push) (widen) (if (or (progn (goto-char (point-min)) (re-search-forward (format \label{%s} label) nil t))) nil (org-mark-ring-goto) (error %s not found label)) (message go back with (org-mark-ring-goto) `C-c &`)) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format (%s) path)) ((eq format (quote latex)) (format \nameref{%s} keyword)))) | -| pageref | (lambda (label) on clicking goto the label. Navigate back with C-c & (org-mark-ring-push) (widen) (if (or (progn (goto-char (point-min)) (re-search-forward (format label:%s\b label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format \label{%s} label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format ^#\+label:\s-*\(%s\)\b label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format ^#\+tblname:\s-*\(%s\)\b label) nil t))) nil (org-mark-ring-goto) (error %s not found label)) (message go back with (org-mark-ring-goto) `C-c &`)) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format (%s) path)) ((eq format (quote latex)) (format \pageref{%s} keyword)))) | -| ref | (lambda (label) on clicking goto the label. Navigate back with C-c & (org-mark-ring-push) (widen) (if (or (progn (goto-char (point-min)) (re-search-forward (format label:%s\b label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format \label{%s} label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format ^#\+label:\s-*\(%s\)\b label) nil t)) (progn (goto-char (point-min)) (re-search-forward (format ^#\+tblname:\s-*\(%s\)\b label) nil t))) nil (org-mark-ring-goto) (error %s not found label)) (org-show-entry) (message go back with (org-mark-ring-goto) `C-c &`)) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format (%s) path)) ((eq format (quote latex)) (format \ref{%s} keyword)))) | -| label | (lambda (label) on clicking count the number of label tags used in the buffer. A number greater than one means multiple labels! (message (format %s occurences (+ (count-matches (format label:%s\b[^-:] label) (point-min) (point-max) t) (count-matches (format ^#\+tblname:\s-*%s\b[^-:] label) (point-min) (point-max) t) (count-matches (format \label{%s}\b label) (point-min) (point-max) t) (count-matches (format ^#\+label:\s-*%s\b[^-:] label) (point-min) (point-max) t))))) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format () path)) ((eq format (quote latex)) (format \label{%s} keyword)))) | -| list-of-tables | org-ref-list-of-tables | (lambda (keyword desc format) (cond ((eq format (quote latex)) (format \listoftables)))) | -| list-of-figures | org-ref-list-of-figures | (lambda (keyword desc format) (cond ((eq format (quote latex)) (format \listoffigures)))) | -| addbibresource | (lambda (link-string) (let* ((bibfile) (object (org-element-context)) (link-string-beginning) (link-string-end)) (save-excursion (goto-char (org-element-property :begin object)) (search-forward link-string nil nil 1) (setq link-string-beginning (match-beginning 0)) (setq link-string-end (match-end 0))) (set (make-local-variable (quote reftex-default-addbibresource)) (split-string (org-element-property :path object) ,)) (save-excursion (if (search-forward , link-string-end 1 1) (setq key-end (- (match-end 0) 1)) (setq key-end (point)))) (save-excursion (if (search-backward , link-string-beginning 1 1) (setq key-beginning (+ (match-beginning 0) 1)) (setq key-beginning (point)))) (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end))) (find-file bibfile))) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format )) ((eq format (quote latex)) (format \addbibresource{%s} keyword)))) | -| bibliographystyle | (lambda (arg) (message Nothing implemented for clicking here.)) | (lambda (keyword desc format) (cond ((eq format (quote latex)) (format \bibliographystyle{%s} keyword)))) | -| printbibliography | (lambda (arg) (message Nothing implemented for clicking here.)) | (lambda (keyword desc format) (cond ((eq format (quote org)) (org-ref-get-org-bibliography)) ((eq format (quote html)) (org-ref-get-html-bibliography)) ((eq format (quote latex)) \printbibliography))) | -| nobibliography | (lambda (link-string) (let* ((bibfile) (object (org-element-context)) (link-string-beginning) (link-string-end)) (save-excursion (goto-char (org-element-property :begin object)) (search-forward link-string nil nil 1) (setq link-string-beginning (match-beginning 0)) (setq link-string-end (match-end 0))) (set (make-local-variable (quote reftex-default-bibliography)) (split-string (org-element-property :path object) ,)) (save-excursion (if (search-forward , link-string-end 1 1) (setq key-end (- (match-end 0) 1)) (setq key-end (point)))) (save-excursion (if (search-backward , link-string-beginning 1 1) (setq key-beginning (+ (match-beginning 0) 1)) (setq key-beginning (point)))) (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end))) (find-file bibfile))) | (lambda (keyword desc format) (cond ((eq format (quote org)) (org-ref-get-org-bibliography)) ((eq format (quote ascii)) (org-ref-get-ascii-bibliography)) ((eq format (quote html)) (org-ref-get-html-bibliography)) ((eq format (quote latex)) (format \nobibliography{%s} (replace-regexp-in-string \.bib (mapconcat (quote identity) (mapcar (quote expand-file-name) (split-string keyword ,)) ,)))))) | -| bibliography | (lambda (link-string) (let* ((bibfile) (object (org-element-context)) (link-string-beginning) (link-string-end)) (save-excursion (goto-char (org-element-property :begin object)) (search-forward link-string nil nil 1) (setq link-string-beginning (match-beginning 0)) (setq link-string-end (match-end 0))) (set (make-local-variable (quote reftex-default-bibliography)) (split-string (org-element-property :path object) ,)) (save-excursion (if (search-forward , link-string-end 1 1) (setq key-end (- (match-end 0) 1)) (setq key-end (point)))) (save-excursion (if (search-backward , link-string-beginning 1 1) (setq key-beginning (+ (match-beginning 0) 1)) (setq key-beginning (point)))) (setq bibfile (org-ref-strip-string (buffer-substring key-beginning key-end))) (find-file bibfile))) | (lambda (keyword desc format) (cond ((eq format (quote org)) (org-ref-get-org-bibliography)) ((eq format (quote ascii)) (org-ref-get-ascii-bibliography)) ((eq format (quote html)) (org-ref-get-html-bibliography)) ((eq format (quote latex)) (format \bibliography{%s} (replace-regexp-in-string \.bib (mapconcat (quote identity) (mapcar (quote expand-file-name) (split-string keyword ,)) ,)))))) | -| rmail | org-rmail-open | nil | -| mhe | org-mhe-open | nil | -| irc | org-irc-visit | nil | -| info | org-info-open | nil | -| gnus | org-gnus-open | nil | -| docview | org-docview-open | org-docview-export | -| bibtex | org-bibtex-open | nil | -| bbdb | org-bbdb-open | org-bbdb-export | -| pydoc | (lambda (link-string) (shell-command (format python -m pydoc %s link-string))) | nil | -| index | (lambda (path) (tq-index) (occur path)) | nil | -| attachfile | (lambda (link-string) (org-open-file link-string)) | (lambda (keyword desc format) (cond ((eq format (quote html)) (format )) ((eq format (quote latex)) (format \attachfile{%s} keyword)))) | -| msx | org-msx-open | nil | -| id | org-id-open | nil | -| file+emacs | org-open-file-with-emacs | nil | -| file+sys | org-open-file-with-system | nil | - - - * Utilities ** create simple text citation from bibtex entry #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-bib-citation () - "from a bibtex entry, create and return a simple citation string." + "From a bibtex entry, create and return a simple citation string. +This assumes you are in an article." (bibtex-beginning-of-entry) (let* ((cb (current-buffer)) @@ -2444,6 +2450,9 @@ If no bibliography is in the buffer the `reftex-default-bibliography' is used." #+END_SRC ** Find bad cite links + :PROPERTIES: + :ID: 8515E800-EDA0-4B2A-85FD-55B6FF849203 + :END: Depending on how you enter citations, you may have citations with no corresponding bibtex entry. This function finds them and gives you a clickable table to navigate to them. #+BEGIN_SRC emacs-lisp :tangle org-ref.el @@ -2501,6 +2510,190 @@ Makes a new buffer with clickable links." (message "No bad cite links found")))) #+END_SRC +** helm interface to org-ref +In [[id:8515E800-EDA0-4B2A-85FD-55B6FF849203][Find bad cite links]] we wrote a function that finds bad links and creates a buffer of links to them. + +Here we develop a similar idea, but instead of an org-buffer with links, we create helm sources for bad cite links, bad ref links, and multiple labels. + +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref-bad-cite-candidates () + "Returns a list of conses (key . marker) where key does not exist in the known bibliography files, and marker points to the key." + (let* ((cp (point)) ; save to return to later + (bibtex-files (org-ref-find-bibliography)) + (bibtex-file-path (mapconcat + (lambda (x) + (file-name-directory (file-truename x))) + bibtex-files ":")) + (bibtex-keys (mapcar (lambda (x) (car x)) + (bibtex-global-key-alist))) + (bad-citations '())) + + (org-element-map (org-element-parse-buffer) 'link + (lambda (link) + (let ((plist (nth 1 link))) + (when (-contains? org-ref-cite-types (plist-get plist ':type)) + (dolist (key (org-ref-split-and-strip-string (plist-get plist ':path)) ) + (when (not (index key bibtex-keys)) + (goto-char (plist-get plist ':begin)) + (re-search-forward key) + (push (cons key (point-marker)) bad-citations))) + )))) + (goto-char cp) + bad-citations)) + +;; It seems I forgot I already defined this earlier! +;; (defun org-ref-get-labels () +;; "Returns a list of known labels in the org document. These include label links, latex labels, label tags, and table names. The list contains all labels, not just unique ones. +;; " +;; (let ((cp (point)) +;; (labels '())) +;; (goto-char (point-min)) +;; (while (re-search-forward "[^#+]label:\\(.*\\)\\s-" nil t) +;; (push (match-string 1) labels)) + +;; (goto-char (point-min)) +;; (while (re-search-forward "\\label{\\(.*\\)}\\s-?" nil t) +;; (push (match-string 1) labels)) + +;; (goto-char (point-min)) +;; (while (re-search-forward "^#\\+label:\\s-*\\(.*\\)" nil t) +;; (push (match-string 1) labels)) + +;; (goto-char (point-min)) +;; (while (re-search-forward "^#\\+tblname:\\s-*\\(.*\\)" nil t) +;; (push (match-string 1) labels)) +;; ;; check for CUSTOM_ID +;; (org-map-entries +;; (lambda () +;; (when (org-entry-get (point) "CUSTOM_ID") +;; (push (org-entry-get (point) "CUSTOM_ID") labels)))) +;; ;; return to original place +;; (goto-char cp) +;; labels)) + + +(defun org-ref-bad-ref-candidates () + "Returns a list of conses (ref . marker) where ref is a ref link that does not point to anything (i.e. a label)." + ;; first get a list of legitimate labels + (let ((cp (point)) + (labels (org-ref-get-labels)) + (bad-refs '())) + ;; now loop over ref links + (goto-char (point-min)) + (org-element-map (org-element-parse-buffer) 'link + (lambda (link) + (let ((plist (nth 1 link))) + (when (or (equal (plist-get plist ':type) "ref") + (equal (plist-get plist ':type) "eqref") + (equal (plist-get plist ':type) "pageref") + (equal (plist-get plist ':type) "nameref")) + (unless (-contains? labels (plist-get plist :path)) + (goto-char (plist-get plist :begin)) + (add-to-list + 'bad-refs + (cons (plist-get plist :path) + (point-marker)))))))) + (goto-char cp) + bad-refs)) + + +(defun org-ref-bad-label-candidates () + "Return a list of labels where label is multiply defined." + (let ((labels (org-ref-get-labels)) + (multiple-labels '())) + (when (not (= (length labels) + (length (-uniq labels)))) + (dolist (label labels) + (when (> (-count (lambda (a) + (equal a label)) + labels) 1) + ;; this is a multiply defined label. + (let ((cp (point))) + (goto-char (point-min)) + (while (re-search-forward + (format "[^#+]label:%s\\s-" label) nil t) + (push (cons label (point-marker)) multiple-labels)) + + (goto-char (point-min)) + (while (re-search-forward + (format "\\label{%s}\\s-?" label) nil t) + (push (cons label (point-marker)) multiple-labels)) + + (goto-char (point-min)) + (while (re-search-forward + (format "^#\\+label:\\s-*%s" label) nil t) + (push (cons label (point-marker)) multiple-labels)) + + (goto-char (point-min)) + (while (re-search-forward + (format "^#\\+tblname:\\s-*%s" label) nil t) + (push (cons label (point-marker)) multiple-labels)) + (goto-char cp))))) + multiple-labels)) +#+END_SRC + +#+RESULTS: +: org-ref-bad-label-candidates + +Now, we have a functions for candidates, we can make helm sources for each one, and then run a helm command to view them. + +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref () + "Opens a helm interface to actions for org-ref. +Shows bad citations, ref links and labels" + (interactive) + (let ((cb (current-buffer)) + (bad-citations (org-ref-bad-cite-candidates)) + (bad-refs (org-ref-bad-ref-candidates)) + (bad-labels (org-ref-bad-label-candidates))) + + (helm :sources `(((name . "Bad citations") + (candidates . ,bad-citations) + (action . (lambda (marker) + (switch-to-buffer (marker-buffer marker)) + (goto-char marker)))) + ;; + ((name . "Bad Labels") + (candidates . ,bad-labels) + (action . (lambda (marker) + (switch-to-buffer (marker-buffer marker)) + (goto-char marker)))) + ;; + ((name . "Bad ref links") + (candidates . ,bad-refs) + (action . (lambda (marker) + (switch-to-buffer (marker-buffer marker)) + (goto-char marker)))) + ;; + ((name . "Utilities") + (candidates . (("Check buffer again" . org-ref) + ("Insert citation" . helm-bibtex) + ("Insert label link" . org-ref-helm-insert-label-link) + ("Insert ref link" . org-ref-helm-insert-ref-link) + ("List of figures" . org-ref-list-of-figures) + ("List of tables" . org-ref-list-of-tables) + ("Table of contents" . nil) + )) + (action . (lambda (x) + (switch-to-buffer ,cb) + (funcall x)))) + ;; + ((name . "Export functions") + (candidates . (("Extract cited entries" . org-ref-extract-bibtex-entries) + ("Export to html and open" . (lambda () (org-open-file (org-html-export-to-html)))) + ("Export to pdf and open" . (lambda () + (org-open-file (org-latex-export-to-pdf)))) + ("Export to manuscript pdf and open" . ox-manuscript-export-and-build-and-open) + ("Export submission manuscript pdf and open" . ox-manuscript-build-submission-manuscript-and-open) + + )) + (action . (lambda (x) + (switch-to-buffer ,cb) + (funcall x)))) + )))) +#+END_SRC + + ** Finding non-ascii characters I like my bibtex files to be 100% ascii. This function finds the non-ascii characters so you can replace them. @@ -2731,6 +2924,147 @@ Sometimes it may be helpful to manually change the order of citations. These fun (add-hook 'org-shiftright-hook (lambda () (org-ref-swap-citation-link 1))) (add-hook 'org-shiftleft-hook (lambda () (org-ref-swap-citation-link -1))) #+END_SRC + +** Lightweight messages about links +To get a lighter weight message about the label, ref and cite links, we define a function that gives us the minibuffer message, without the menu. We run this in an idle timer. + +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref-get-label-context (label) + "Return a string of context around a label." + (save-excursion + (catch 'result + (goto-char (point-min)) + (when (re-search-forward + (format "label:%s\\b" label) nil t) + (throw 'result (buffer-substring + (progn + (previous-line) + (beginning-of-line) + (point)) + (progn + (forward-line 4) + (point))))) + + (goto-char (point-min)) + (when (re-search-forward + (format "\\label{%s}" label) nil t) + (throw 'result (buffer-substring + (progn + (previous-line) + (beginning-of-line) + (point)) + (progn + (forward-line 4) + (point))))) + + (goto-char (point-min)) + (when (re-search-forward + (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t) + (throw 'result (buffer-substring + (progn + (previous-line) + (beginning-of-line) + (point)) + (progn + (forward-line 4) + (point))))) + + (goto-char (point-min)) + (when (re-search-forward + (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t) + (throw 'result (buffer-substring + (progn + (previous-line) + (beginning-of-line) + (point)) + (progn + (forward-line 4) + (point))))) + + ;; maybe we have a CUSTOM-ID + (org-map-entries + (lambda () (when (string= + label + (org-entry-get (point) "CUSTOM_ID")) + (throw 'result (org-get-heading))))) + (beep) + (throw 'result "!!! NO CONTEXT FOUND !!!")))) + + +(defun org-ref-link-message () + "Print a minibuffer message about the link that point is on." + (interactive) + (when (eq major-mode 'org-mode) + (let* ((object (org-element-context)) + (type (org-element-property :type object))) + (save-excursion + (cond + ;; cite links + ((-contains? org-ref-cite-types type) + (message (org-ref-get-citation-string-at-point))) + + ;; message some context about the label we are referring to + ((string= type "ref") + (message (org-ref-get-label-context + (org-element-property :path object)))) + + ((string= type "eqref") + (message (org-ref-get-label-context + (org-element-property :path object)))) + + ;; message the count + ((string= type "label") + (let ((count (org-ref-count-labels + (org-element-property :path object)))) + ;; get plurality on occurrence correct + (when (> count 1) (beep)) + (message (concat + (number-to-string count) + " occurence" + (when (or (= count 0) + (> count 1)) + "s"))))) + + ;; check if the bibliography files exist. + ((string= type "bibliography") + (let* ((bibfile) + ;; object is the link you clicked on + (object (org-element-context)) + (link-string (org-element-property :path object)) + (link-string-beginning) + (link-string-end)) + + (save-excursion + (goto-char (org-element-property :begin object)) + (search-forward link-string nil nil 1) + (setq link-string-beginning (match-beginning 0)) + (setq link-string-end (match-end 0))) + + ;; now if we have comma separated bibliographies + ;; we find the one clicked on. we want to + ;; search forward to next comma from point + (save-excursion + (goto-char link-string-beginning) + (if (search-forward "," link-string-end 1 1) + (setq key-end (- (match-end 0) 1)) ; we found a match + (setq key-end (point)))) ; no comma found so take the point + ;; and backward to previous comma from point + (save-excursion + (goto-char link-string-beginning) + (if (search-backward "," link-string-beginning 1 1) + (setq key-beginning (+ (match-beginning 0) 1)) ; we found a match + (setq key-beginning (point)))) ; no match found + ;; save the key we clicked on. + (setq bibfile + (org-ref-strip-string + (buffer-substring key-beginning key-end))) + (if (file-exists-p bibfile) + (message "%s exists." bibfile) + (beep) + (message "!!! %s NOT FOUND !!!" bibfile)))) + ))))) +#+END_SRC + * Aliases I like convenience. Here are some aliases for faster typing. @@ -2749,6 +3083,272 @@ I like convenience. Here are some aliases for faster typing. (defalias 'orcb 'org-ref-clean-bibtex-entry) #+END_SRC +* Helm interface +[[https://github.com/tmalsburg/helm-bibtex][helm-bibtex]] is a very cool interface to bibtex files. Out of the box though, it is not super convenient for org-ref. Here, we modify it to make it fit our workflow and extend it where needed. + +1. Make the default action to insert selected keys. +2. Make open entry second action +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(setq helm-source-bibtex + '((name . "BibTeX entries") + (init . helm-bibtex-init) + (candidates . helm-bibtex-candidates) + (filtered-candidate-transformer . helm-bibtex-candidates-formatter) + (action . (("Insert citation" . helm-bibtex-insert-citation) + ("Show entry" . helm-bibtex-show-entry) + ("Open PDF file (if present)" . helm-bibtex-open-pdf) + ("Open URL or DOI in browser" . helm-bibtex-open-url-or-doi) + ("Insert reference" . helm-bibtex-insert-reference) + ("Insert BibTeX key" . helm-bibtex-insert-key) + ("Insert BibTeX entry" . helm-bibtex-insert-bibtex) + ("Attach PDF to email" . helm-bibtex-add-PDF-attachment) + ("Edit notes" . helm-bibtex-edit-notes) + )))) +#+END_SRC + +Now, let us define a function that inserts the cite links: +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun helm-bibtex-format-org-ref (keys) + "Insert selected KEYS as cite link. Append KEYS if you are on a link. +Technically, this function should return a string that is inserted by helm. This function does the insertion and gives helm an empty string to insert. This lets us handle appending to a link properly. + +In the helm-bibtex buffer, C-u will give you a helm menu to select a new link type for the selected entries. + +C-u C-u will change the key at point to the selected keys. +" + (let* ((object (org-element-context))) + (cond + ;; case where we are in a link + ((and (equal (org-element-type object) 'link) + (-contains? + org-ref-cite-types + (org-element-property :type object))) + (cond + ;; no prefix. append keys + ((equal helm-current-prefix-arg nil) + (goto-char (org-element-property :end object)) + (while (looking-back " ") (backward-char)) + (insert (concat "," (mapconcat 'identity keys ",")))) + ;; double prefix, replace key at point + ((equal helm-current-prefix-arg '(16)) + (setf (buffer-substring + (org-element-property :begin object) + (org-element-property :end object)) + (concat + (replace-regexp-in-string + (car (org-ref-get-bibtex-key-and-file)) ; key + (mapconcat 'identity keys ",") ; new keys + (org-element-property :raw-link object) + ) + ;; replace space at end to avoid collapsing into next word. + " "))) + (t + (message "Not found")))) + + ;; We are next to a link, and we want to append + ;; next to a link means one character back is on a link. + ((save-excursion + (backward-char) + (and (equal (org-element-type (org-element-context)) 'link) + (-contains? + org-ref-cite-types + (org-element-property :type (org-element-context))))) + ;;(message-box "at end of a link") + ;; (goto-char (org-element-property :end object)) + (while (looking-back " ") (backward-char)) + (insert (concat "," (mapconcat 'identity keys ",")))) + + ;; insert fresh link + (t + ;;(message-box "fresh link") + (insert + (concat (if (equal helm-current-prefix-arg '(4)) + (helm :sources `((name . "link types") + (candidates . ,org-ref-cite-types) + (action . (lambda (x) x)))) + org-ref-default-citation-link) + ":" + (s-join "," keys)))))) + ;; return empty string for helm + "") + +(setq helm-bibtex-format-citation-functions + '((org-mode . helm-bibtex-format-org-ref))) + +(defun org-ref-helm-insert-cite-link () + "org-ref function to use helm on the bibliography defined in the org-file." + (interactive) + (let ((helm-bibtex-bibliography (org-ref-find-bibliography))) + (helm-bibtex))) + +(require 'helm-bibtex) + +;; add our own fallback entries where we want them. These appear in reverse order of adding in the menu +(setq helm-bibtex-fallback-options + (-insert-at 1 '("Crossref" . "http://search.crossref.org/?q=%s") helm-bibtex-fallback-options)) + +(setq helm-bibtex-fallback-options + (-insert-at + 1 + '("Scopus" . "http://www.scopus.com/scopus/search/submit/xadvanced.url?searchfield=TITLE-ABS-KEY(%s)") + helm-bibtex-fallback-options)) + +(setq helm-bibtex-fallback-options + (-insert-at 1 '("Open Web of Science" . (lambda () (browse-url "http://apps.webofknowledge.com"))) + helm-bibtex-fallback-options)) +#+END_SRC + +** A helm click menu +This code provides a helm interface to things you can do when you click on a citation link. This is an alternative to the minibuffer menu. +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref-get-citation-string-at-point () + "Get a string of a formatted citation" + (interactive) + (let* ((results (org-ref-get-bibtex-key-and-file)) + (key (car results)) + (bibfile (cdr results))) + (if bibfile + (save-excursion + (with-temp-buffer + (insert-file-contents bibfile) + (bibtex-search-entry key) + (org-ref-bib-citation))) + (beep) + "!!! No entry found !!!" ))) + +(defun org-ref-cite-candidates () + "Generate the list of possible candidates for click actions on a cite link. +Checks for pdf and doi, and add appropriate functions." + (interactive) + (let* ((results (org-ref-get-bibtex-key-and-file)) + (key (car results)) + (pdf-file (format (concat org-ref-pdf-directory "%s.pdf") key)) + (bibfile (cdr results)) + (url (save-excursion + (with-temp-buffer + (insert-file-contents bibfile) + (bibtex-search-entry key) + (bibtex-autokey-get-field "url")))) + (doi (save-excursion + (with-temp-buffer + (insert-file-contents bibfile) + (bibtex-search-entry key) + ;; I like this better than bibtex-url which does not always find + ;; the urls + (bibtex-autokey-get-field "doi")))) + (candidates `(("Quit" . org-ref-citation-at-point) + ("Open bibtex entry" . org-ref-open-citation-at-point)))) + ;; for some reason, when there is no doi or url, they are returned as "". I + ;; prefer nil so we correct this here. + (when (string= doi "") (setq doi nil)) + (when (string= url "") (setq url nil)) + + ;; Conditional pdf functions + (if (file-exists-p pdf-file) + (add-to-list + 'candidates + '("Open pdf" . org-ref-open-pdf-at-point) + t) + (add-to-list + 'candidates + '("Try to get pdf" . (lambda () + (save-window-excursion + (org-ref-open-citation-at-point) + (bibtex-beginning-of-entry) + (doi-utils-get-bibtex-entry-pdf)))) + t)) + + + (add-to-list + 'candidates + '("Open notes" . org-ref-open-notes-at-point) + t) + + ;; conditional url and doi functions + (when (or url doi) + (add-to-list + 'candidates + '("Open in browser" . org-ref-open-url-at-point) + t)) + + (when doi + (mapc (lambda (x) + (add-to-list 'candidates x t)) + `(("WOS" . org-ref-wos-at-point) + ("Related articles in WOS" . org-ref-wos-related-at-point) + ("Citing articles in WOS" . org-ref-wos-citing-at-point) + ("Google Scholar" . org-ref-google-scholar-at-point) + ("Pubmed" . org-ref-pubmed-at-point) + ("Crossref" . org-ref-crossref-at-point) + ))) + + (add-to-list + 'candidates + '("Copy formatted citation to clipboard" . org-ref-copy-entry-as-summary) + t) + + (add-to-list + 'candidates + '("Copy key to clipboard" . (lambda () + (kill-new + (car (org-ref-get-bibtex-key-and-file))))) + t) + + (add-to-list + 'candidates + '("Copy bibtex entry to file" . org-ref-copy-entry-at-point-to-file) + t) + + (add-to-list + 'candidates + '("Email bibtex entry and pdf" . (lambda () + (save-excursion + (org-ref-open-citation-at-point) + (email-bibtex-entry)))) + t) + ;; finally return a numbered list of the candidates + (loop for i from 0 + for cell in candidates + collect (cons (format "%2s. %s" i (car cell)) + (cdr cell))))) + + +(defvar org-ref-helm-user-candidates '() + "List of user-defined candidates to act when clicking on a cite link. +This is a list of cons cells '((\"description\" . action)). The action function should not take an argument, and should assume point is on the cite key of interest. +") + +;; example of adding your own function +(add-to-list + 'org-ref-helm-user-candidates + '("Example" . (lambda () (message-box "You did it!"))) + t) + +(defun org-ref-cite-click-helm (key) + "subtle points. +1. get name and candidates before entering helm because we need the org-buffer. +2. switch back to the org buffer before evaluating the action. most of them need the point and buffer." + (interactive) + (let ((name (org-ref-get-citation-string-at-point)) + (candidates (org-ref-cite-candidates)) + (cb (current-buffer))) + + (helm :sources `(((name . ,name) + (candidates . ,candidates) + (action . (lambda (f) + (switch-to-buffer cb) + (funcall f)))) + ((name . "User functions") + (candidates . ,org-ref-helm-user-candidates) + (action . (lambda (f) + (switch-to-buffer cb) + (funcall f)))) + )))) +#+END_SRC + +#+RESULTS: +: org-ref-cite-click-helm + * End of code #+BEGIN_SRC emacs-lisp :tangle org-ref.el (provide 'org-ref)