X-Git-Url: https://git.donarmstrong.com/?p=org-ref.git;a=blobdiff_plain;f=org-ref.org;h=e0ce7436c73dad8003305084649947cb302bab0a;hp=0c7e0e9549c0e8544482ffe4b86e7fc38aa788df;hb=dbf4fc3bfed591ebffab129abc3ad6359bea97fa;hpb=b561cfab15de147101e070a568f0ba343505ae41 diff --git a/org-ref.org b/org-ref.org index 0c7e0e9..e0ce743 100644 --- a/org-ref.org +++ b/org-ref.org @@ -12,6 +12,20 @@ This document is an experiment at creating a literate program to provide similar 4. Exportable links to LaTeX 5. Utility functions for dealing with bibtex files and org-files +Some additional features include +1. Get minibuffer messages for the cite/ref/label link under point + +With helm integration (default) you can: + +1. C-c ] to insert a citation link + in helm-bibtex + - Enter to insert or append citation(s) + - C-u Enter to insert an alternative cite link + - C-u C-u Enter to replace the citation at point +2. C-u C-c ] to insert a ref link with helm completion +3. C-u C-u C-c ] to insert a label with completion +4. M-x org-ref to get a helm completion buffer with link checks, utilities and export options + ** Header #+BEGIN_SRC emacs-lisp :tangle org-ref.el ;;; org-ref.el --- setup bibliography, cite, ref and label org-mode links. @@ -52,6 +66,7 @@ The only external require is reftex-cite (require 'reftex-cite) (require 'dash) (require 'helm) +(require 'helm-config) (require 'helm-bibtex) #+END_SRC @@ -128,18 +143,19 @@ There are some variables needed later to tell this library where you store your (defcustom org-ref-insert-cite-function - 'helm-bibtex - "Function to call to insert citation links. The default is `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." + '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." + "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. If you like `hydra', consider using `org-ref-cite-hydra'." :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" @@ -218,11 +234,15 @@ 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-function)) + (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) (add-hook 'org-mode-hook 'org-mode-reftex-setup) @@ -259,6 +279,195 @@ You can define a new citation link like this: (org-ref-define-citation-link "citez" ?z) #+END_SRC +** Messages for link at cursor +Here we setup code that shows you a context message for the element under the cursor when emacs is idle. +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defvar org-ref-message-timer nil + "Variable to store the link message timer in.") + + +(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) + (or org-ref-message-timer + (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) + (setq org-ref-message-timer nil)) + + +(when org-ref-show-citation-on-enter + (org-ref-show-link-messages)) + +;; 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)) +#+END_SRC + +** Messages for context under mouse pointer +Sometimes, when reading a document, I actually use the mouse more than the cursor. This code enables the mouse cursor to trigger a message in the minibuffer about what is under the cursor. I run this on a timer. + +The basic idea here is to get the mouse position, and if we can determine there is a character that (point) can move to, we move (point) and run the org-ref-link-message function. Since this runs on a timer, we store the last mouse position, and only run the function when the mouse has moved to avoid getting messages every time the timer runs. + +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defvar org-ref-last-mouse-pos nil + "Stores last mouse position for use in `org-ref-mouse-message'.") + +(defun org-ref-can-move-p () + "See if a character is under the mouse. If so return the position for `goto-char'." + (let* ((line (cddr org-ref-last-mouse-pos)) + (col (cadr org-ref-last-mouse-pos))) + (save-excursion + (goto-char (window-start)) + (forward-line line) + (if + (> (- (line-end-position) (line-beginning-position)) col) + (progn (forward-char col) (point)) + nil)))) + + +(defun org-ref-mouse-message () + "Display message for link under mouse cursor" + (interactive) + (when (not (equal (mouse-position) org-ref-last-mouse-pos)) + (setq org-ref-last-mouse-pos (mouse-position)) + (let ((p (org-ref-can-move-p))) + (when p + (save-excursion + (goto-char p) + (org-ref-link-message)))))) + + +(defvar org-ref-message-timer-mouse nil + "Store mouse timer.") + + +(defvar org-ref-mouse-message-interval 0.5 + "How often to run the mouse message timer in seconds") + + +(defun org-ref-mouse-messages-on () + "Turn on mouse messages." + (interactive) + (or org-ref-message-timer-mouse + (setq org-ref-message-timer-mouse + (run-at-time "0.5 sec" + org-ref-mouse-message-interval + 'org-ref-mouse-message)))) + + +(defun org-ref-mouse-messages-off () + "Turn off mouse messages" + (interactive) + (cancel-timer org-ref-message-timer-mouse) + (setq org-ref-message-timer-mouse nil) + (message "Mouse messages are off")) +#+END_SRC + +#+RESULTS: +: org-ref-mouse-messages-off + +** Color-coded links +Here we make the org-ref links a different color. + +citations are green +refs are blue +labels are black + +mailto:john + +cite:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc + +cite*:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc + +citenum:sokalski-2012-optim-ta,zhang-2011-spatial-tio2,li-2012-heter-ceram,li-2013-photoc + +ref:test + +label:test + +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defcustom org-ref-colorize-links + t + "When non-nil, change colors of links" + :group 'org-ref) + + +(defcustom org-ref-cite-color + "forest green" + "Color of cite like links" + :group 'org-ref) + + +(defcustom org-ref-ref-color + "dark red" + "Color of ref like links" + :group 'org-ref) + + +(defcustom org-ref-label-color + "dark magenta" + "Color of label links" + :group 'org-ref) + + +(defvar org-ref-cite-re nil + "regexp for cite links") + + +(setq org-ref-cite-re + (concat "\\(" (mapconcat + (lambda (x) + (replace-regexp-in-string "\*" "\\\\*" x) + ) + org-ref-cite-types "\\|") "\\)" + ":\\([a-zA-Z0-9-_:]*,?\\)*")) + + +(setq org-ref-label-re + "label:\\([a-zA-Z0-9-_:]*,?\\)*") + + +(setq org-ref-ref-re + "ref:\\([a-zA-Z0-9-_:]*,?\\)*") + + +(defface org-ref-cite-face + `((t (:inherit org-link :foreground ,org-ref-cite-color))) + "Color for cite-like links in org-ref.") + + +(defface org-ref-label-face + `((t (:inherit org-link :foreground ,org-ref-label-color))) + "Color for ref links in org-ref.") + + +(defface org-ref-ref-face + `((t (:inherit org-link :foreground ,org-ref-ref-color))) + "Face for ref links in org-ref.") + + +(defun org-ref-colorize-links () + "Colorize org-ref links." + (hi-lock-mode 1) + (highlight-regexp org-ref-cite-re 'org-ref-cite-face) + (highlight-regexp org-ref-label-re 'org-ref-label-face) + (highlight-regexp org-ref-ref-re 'org-ref-ref-face)) + + +(when org-ref-colorize-links + (add-hook 'org-mode-hook 'org-ref-colorize-links)) +#+END_SRC + +#+RESULTS: + + * Links Most of this library is the creation of functional links to help with references and citations. ** General utilities @@ -447,7 +656,7 @@ This code provides some functions to generate a simple sorted bibliography in ht #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-get-bibtex-keys () - "return a list of unique keys in the buffer." + "Return a list of unique keys in the buffer." (let ((keys '())) (org-element-map (org-element-parse-buffer) 'link (lambda (link) @@ -457,7 +666,9 @@ This code provides some functions to generate a simple sorted bibliography in ht (key (org-ref-split-and-strip-string (plist-get plist ':path))) (when (not (-contains? keys key)) - (setq keys (append keys (list key))))))))) + (setq keys (append keys (list key)))))))) + ;; set with-affiliated to get keys in captions + nil nil nil t) ;; Sort keys alphabetically (setq keys (cl-sort keys 'string-lessp :key 'downcase)) keys)) @@ -575,7 +786,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)) @@ -889,23 +1099,37 @@ 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)) + ;; 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)) + (count-matches (format "\\label{%s}" label) (point-min) (point-max)) + ;; this is the org-format #+label: + (count-matches (format "^#\\+label:\\s-*%s\\b[^-:]" label) (point-min) (point-max)) + (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))))) + (let ((count (org-ref-count-labels label))) + (message (format "%s occurence%s" + count + (if (or (= count 0) + (> count 1)) + "s" + "")) + (org-ref-count-labels label)))) (lambda (keyword desc format) (cond ((eq format 'html) (format "()" path)) @@ -1013,7 +1237,7 @@ It would be nice to use completion to enter a ref link, where a list of labels i #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-get-org-labels () - "find #+LABEL: labels" + "Return a list of #+LABEL: labels." (save-excursion (goto-char (point-min)) (let ((matches '())) @@ -1024,7 +1248,7 @@ matches))) #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-get-custom-ids () - "return a list of custom_id properties in the buffer" + "Return a list of custom_id properties in the buffer." (let ((results '()) custom_id) (org-map-entries (lambda () @@ -1049,6 +1273,7 @@ Finally, we get the table names. #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-get-tblnames () + "Return list of table names in the buffer." (org-element-map (org-element-parse-buffer 'element) 'table (lambda (table) (org-element-property :name table)))) @@ -1058,18 +1283,100 @@ Now, we can put all the labels together which will give us a list of candidates. #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-get-labels () - "returns a list of labels in the buffer that you can make a ref link to. this is used to auto-complete ref links." + "Returns a list of labels in the buffer that you can make a ref link to. +This is used to auto-complete ref links and in helm menus." (save-excursion (save-restriction (widen) (goto-char (point-min)) (let ((matches '())) - (while (re-search-forward "label:\\([a-zA-z0-9:-]*\\)" (point-max) t) + ;; these are the label:stuff kinds + (while (re-search-forward "[^#+]label:\\([a-zA-z0-9:-]*\\)" (point-max) t) (add-to-list 'matches (match-string-no-properties 1) t)) - (append matches (org-ref-get-org-labels) (org-ref-get-latex-labels) (org-ref-get-tblnames) (org-ref-get-custom-ids)))))) + (append matches + (org-ref-get-org-labels) + (org-ref-get-latex-labels) + (org-ref-get-tblnames) + (org-ref-get-custom-ids)))))) #+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. +Let us make a helm function to insert a label link. This will help you enter unique labels by showing matching labels until they are all gone and you are left with a unique one. If you are on a link, it means you want to replace it. +#+BEGIN_SRC emacs-lisp :tangle org-ref.el +(defun org-ref-helm-insert-label-link () + "Insert a label link. helm just shows you what labels already exist. +If you are on a label link, replace it." + (interactive) + (let* ((labels (org-ref-get-labels)) + (cb (current-buffer))) + (helm :sources `(((name . "Existing labels") + (candidates . ,labels) + ;; default action is to open to the label + (action . (lambda (label) + ;; unfortunately I do not have markers here + (org-open-link-from-string (format "ref:%s" label)))) + ;; if you select a label, replace current one + (action . (lambda (label) + (switch-to-buffer ,cb) + (cond + ;; no prefix or on a link + ((equal helm-current-prefix-arg nil) + (let* ((object (org-element-context)) + (last-char (save-excursion + (goto-char (org-element-property :end object)) + (backward-char) + (if (looking-at " ") + " " + "")))) + (when (-contains? '("label") + (org-element-property :type object)) + ;; we are on a link, so replace it. + (setf + (buffer-substring + (org-element-property :begin object) + (org-element-property :end object)) + (concat + (replace-regexp-in-string + (org-element-property :path object) + label + (org-element-property :raw-link object)) + last-char))))) + ;; no prefix options defined + )))) + ;; no matching selection creates a new label + ((name . "Create new label") + (dummy) + ;; default action creates a new label, or replaces old one + (action . (lambda (label) + (switch-to-buffer ,cb) + (let* ((object (org-element-context)) + (last-char (save-excursion + (goto-char (org-element-property :end object)) + (backward-char) + (if (looking-at " ") + " " + "")))) + (if (-contains? '("label") + (org-element-property :type object)) + ;; we are on a link, so replace it. + (setf + (buffer-substring + (org-element-property :begin object) + (org-element-property :end object)) + (concat + (replace-regexp-in-string + (org-element-property :path object) + helm-pattern + (org-element-property :raw-link object)) + last-char)) + ;; new link + (insert + (concat + "label:" + (or label + helm-pattern)))))))))))) +#+END_SRC + +Now we create a 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 (defun org-ref-complete-link (&optional arg) @@ -1087,6 +1394,89 @@ 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 :tangle org-ref.el +(defun org-ref-helm-insert-ref-link () + "Helm menu to insert ref links to labels in the document. +If you are on link, replace with newly selected label. +Use C-u to insert a different kind of ref link. +Use C-u C-u to insert a [[#custom-id]] link +" + (interactive) + (let* ((labels (org-ref-get-labels)) + (bs (buffer-string)) + (contexts (with-temp-buffer + (insert bs) + (mapcar 'org-ref-get-label-context labels))) + (cb (current-buffer))) + + (helm :input (thing-at-point 'word) + :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))) + ;; default action to replace or insert ref link. + (action . (lambda (label) + (switch-to-buffer ,cb) + + (cond + ;; no prefix or on a link + ((equal helm-current-prefix-arg nil) + (let* ((object (org-element-context)) + (last-char (save-excursion + (goto-char (org-element-property :end object)) + (backward-char) + (if (looking-at " ") + " " + "")))) + (if (-contains? '("ref" "eqref" "pageref" "nameref") + (org-element-property :type object)) + ;; we are on a link, so replace it. + (setf + (buffer-substring + (org-element-property :begin object) + (org-element-property :end object)) + (concat + (replace-regexp-in-string + (org-element-property :path object) + label + (org-element-property :raw-link object)) + last-char)) + ;; insert a new link + (insert + (concat + "ref:" label)) + ))) + ;; one prefix, alternate ref link + ((equal helm-current-prefix-arg '(4)) + (insert + (concat + (helm :sources '((name . "Ref link types") + (candidates . ("ref" "eqref" "pageref" "nameref")) + (action . (lambda (x) x)))) + ":" label))) + ;; two prefixes, insert section custom-id link + ((equal helm-current-prefix-arg '(16)) + (insert + (format "[[#%s]]" label))) + )) + )))))) +#+END_SRC + +#+RESULTS: +: org-ref-helm-insert-ref-link + ** pageref This refers to the page of a label in LaTeX. @@ -1330,9 +1720,15 @@ Now, we can see if an entry is in a file. #+BEGIN_SRC emacs-lisp :tangle org-ref.el (defun org-ref-key-in-file-p (key filename) "determine if the key is in the file" - (interactive "skey: \nsFile: ") (save-current-buffer (let ((bibtex-files (list filename))) + ;; This is something I am trying because when the bibtex file is open, and + ;; you have added to it, the only way I find to get the update to update + ;; is to close it and reopen it. or to save it and revert it. + (when (get-file-buffer filename) + (set-buffer (get-file-buffer filename)) + (save-buffer) + (revert-buffer t t)) (bibtex-search-entry key t)))) #+END_SRC @@ -1386,14 +1782,14 @@ We need some convenience functions to open act on the citation at point. These w (catch 'done (let ((url (bibtex-autokey-get-field "url"))) (when url - (browse-url url) + (browse-url (s-trim url)) (throw 'done nil))) (let ((doi (bibtex-autokey-get-field "doi"))) (when doi (if (string-match "^http" doi) (browse-url doi) - (browse-url (format "http://dx.doi.org/%s" doi))) + (browse-url (format "http://dx.doi.org/%s" (s-trim doi)))) (throw 'done nil)))))))) @@ -1725,7 +2121,25 @@ We will want to generate formatting functions for each citation type. The reason ;; bibtex format (concat "\\" ,type (when desc (org-ref-format-citation-description desc)) "{" (mapconcat (lambda (key) key) (org-ref-split-and-strip-string keyword) ",") - "}")))))) + "}"))) + ;; for markdown we generate pandoc citations + ((eq format 'md) + (cond + (desc ;; pre and or post text + (let* ((text (split-string desc "::")) + (pre (car text)) + (post (cadr text))) + (concat + (format "[@%s," keyword) + (when pre (format " %s" pre)) + (when post (format ", %s" post)) + "]"))) + (t + (format "[%s]" + (mapconcat + (lambda (key) (concat "@" key)) + (org-ref-split-and-strip-string keyword) + "; ")))))))) #+END_SRC @@ -2019,120 +2433,6 @@ 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 @@ -2348,8 +2648,8 @@ Here is the python script for uploading. *************** TODO document how to get the cookies *************** END - -#+BEGIN_SRC python :tangle upload_bibtex_citeulike.py +# :tangle upload_bibtex_citeulike.py +#+BEGIN_SRC python #!python import pickle, requests, sys @@ -2473,6 +2773,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 @@ -2506,13 +2809,21 @@ Makes a new buffer with clickable links." (org-element-map (org-element-parse-buffer) 'link (lambda (link) (let ((plist (nth 1 link))) - (when (equal (plist-get plist ':type) "cite") - (dolist (key (org-ref-split-and-strip-string (plist-get plist ':path)) ) + (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)) - (setq bad-citations (append bad-citations - `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n" - key (buffer-name)(plist-get plist ':begin))))) - )))))) + (message-box "%s" link) + (setq + bad-citations + (append + bad-citations + `(,(format "%s [[elisp:(progn (switch-to-buffer-other-frame \"%s\")(goto-char %s))][not found here]]\n" + key + (buffer-name) + (plist-get plist :begin))))) + ))))) + ;; set with-affilates to t to get citations in a caption + nil nil nil t) (if bad-citations (progn @@ -2530,6 +2841,162 @@ 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))) + ))) + ;; add with-affiliates to get cites in caption + nil nil nil t) + (goto-char cp) + bad-citations)) + + +(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. @@ -2760,6 +3227,151 @@ 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))))) + (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 "%scount: %s" + (org-ref-get-label-context + (org-element-property :path object)) + (org-ref-count-labels + (org-element-property :path object)))) + + ((string= type "eqref") + (message "%scount: %s" + (org-ref-get-label-context + (org-element-property :path object)) + (org-ref-count-labels + (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 + (message (concat + (number-to-string count) + " occurence" + (when (or (= count 0) + (> count 1)) + "s"))))) + + ((string= type "custom-id") + (save-excursion + (org-open-link-from-string + (format "[[#%s]]" (org-element-property :path object))) + (message "%s" (org-get-heading)))) + + ;; 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))) + + ;; make sure we are in link and not before the : + (when (> link-string-beginning (point)) + (goto-char link-string-beginning)) + + ;; 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 + (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 + (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) + (message "!!! %s NOT FOUND !!!" bibfile)))) + ))))) +#+END_SRC + * Aliases I like convenience. Here are some aliases for faster typing. @@ -2804,56 +3416,129 @@ I like convenience. Here are some aliases for faster typing. 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." - (let* ((object (org-element-context))) + "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)) + (last-char (save-excursion + (goto-char (org-element-property :end object)) + (backward-char) + (if (looking-at " ") + " " + "")))) (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))) - (goto-char link-string-end) - ;; sometimes there are spaces at the end of the link - ;; this code moves point pack until no spaces are there - (while (looking-back " ") (backward-char)) - (insert (concat "," (mapconcat 'identity keys ",")))) + (-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. + last-char)) + ;; and we want to go to the end of the new link + (goto-char + (org-element-property :end (org-element-context)))) + (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))))) + (-contains? + org-ref-cite-types + (org-element-property :type (org-element-context))))) (while (looking-back " ") (backward-char)) (insert (concat "," (mapconcat 'identity keys ",")))) ;; insert fresh link (t + ;;(message-box "fresh link") (insert - (concat org-ref-default-citation-link + (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 ","))))))) + (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 (arg) + "org-ref function to use helm-bibtex to insert a citation link. +With one prefix arg, insert a ref link. +With two prefix args, insert a label link." + (interactive "P") + (cond + ((equal arg nil) + (let ((helm-bibtex-bibliography (org-ref-find-bibliography))) + (helm-bibtex))) + ((equal arg '(4)) + (org-ref-helm-insert-ref-link)) + ((equal arg '(16)) + (org-ref-helm-insert-label-link)))) + (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 '("WOS" . "http://gateway.webofknowledge.com/gateway/Gateway.cgi?topic=%s&GWVersion=2&SrcApp=WEB&SrcAuth=HSB&DestApp=UA&DestLinkType=GeneralSearchSummary") 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))) - (save-excursion - (with-temp-buffer - (insert-file-contents bibfile) - (bibtex-search-entry key) - (org-ref-bib-citation))))) + (if bibfile + (save-excursion + (with-temp-buffer + (insert-file-contents bibfile) + (bibtex-search-entry key) + (org-ref-bib-citation))) + "!!! No entry found !!!" ))) + (defun org-ref-cite-candidates () - "Generate the list of possible candidates. -Check for pdf and doi, and add appropriate functions." + "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)) @@ -2871,23 +3556,35 @@ Check for pdf and doi, and add appropriate functions." ;; I like this better than bibtex-url which does not always find ;; the urls (bibtex-autokey-get-field "doi")))) - (candidates `( ;;the first candidate is a brief summary - ("Quit" . org-ref-citation-at-point) + (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)) - - (when (file-exists-p pdf-file) + ;; 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 - '("Open pdf" . org-ref-open-pdf-at-point) - t - )) + '("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 @@ -2972,18 +3669,40 @@ This is a list of cons cells '((\"description\" . action)). The action function #+RESULTS: : org-ref-cite-click-helm -To get a lighter weight message about the cite link, we define a function that gives us the minibuffer message, without the menu. We add it to a hook that updates after every command, including cursor movements. +** A hydra click interface +I like hydra a lot. Here we define a hydra menu you might like for the link click action. #+BEGIN_SRC emacs-lisp :tangle org-ref.el -(defun org-ref-cite-link-p () (interactive) - (let* ((object (org-element-context)) - (type (org-element-property :type object))) - ;; We only want this to work on citation links - (when (-contains? org-ref-cite-types type) - (message (org-ref-get-citation-string-at-point))))) - -(when org-ref-show-citation-on-enter - (add-hook 'post-command-hook 'org-ref-cite-link-p)) +(when (featurep 'hydra) + (require 'hydra) + (setq hydra-is-helpful t) + + (defhydra org-ref-cite-hydra (:color blue) + " +_p_: Open pdf _w_: WOS _g_: Google Scholar _K_: Copy citation to clipboard +_u_: Open url _r_: WOS related _P_: Pubmed _k_: Copy key to clipboard +_n_: Open notes _c_: WOS citing _C_: Crossref _f_: Copy bibtex entry to file +_o_: Open entry _e_: Email entry and pdf +" + ("o" org-ref-open-citation-at-point nil) + ("p" org-ref-open-pdf-at-point nil) + ("n" org-ref-open-notes-at-point nil) + ("u" org-ref-open-url-at-point nil) + ("w" org-ref-wos-at-point nil) + ("r" org-ref-wos-related-at-point nil) + ("c" org-ref-wos-citing-at-point nil) + ("g" org-ref-google-scholar-at-point nil) + ("P" org-ref-pubmed-at-point nil) + ("C" org-ref-crossref-at-point nil) + ("K" org-ref-copy-entry-as-summary nil) + ("k" (progn + (kill-new + (car (org-ref-get-bibtex-key-and-file)))) nil) + ("f" org-ref-copy-entry-at-point-to-file nil) + + ("e" (save-excursion + (org-ref-open-citation-at-point) + (email-bibtex-entry)) nil))) #+END_SRC * End of code