-*** the links
-We use a link for the bibliography so that we can click on it to open the bibliography file. The link may have more than one bibliography file in it, separated by commas. Clicking opens the file under the cursor. The bibliographies should be full filenames with the bib extension. Clicking on this link makes reftex-default-bibliography local and sets it to the list of files in the link. We need this to use reftex's searching capability.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type "bibliography"
- ;; this code is run on clicking. The bibliography
- ;; may contain multiple files. this code finds the
- ;; one you clicked on and opens it.
- (lambda (link-string)
- ;; get link-string boundaries
- ;; we have to go to the beginning of the line, and then search forward
-
- (let* ((bibfile)
- ;; object is the link you clicked on
- (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)))
-
- ;; We set the reftex-default-bibliography
- ;; here. it should be a local variable only in
- ;; the current buffer. We need this for using
- ;; reftex to do citations.
- (set (make-local-variable 'reftex-default-bibliography)
- (split-string (org-element-property :path object) ","))
-
- ;; 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)))
- (find-file bibfile))) ; open file on click
-
- ;; formatting code
- (lambda (keyword desc format)
- (cond
- ((eq format 'org) (org-ref-get-org-bibliography))
- ((eq format 'ascii) (org-ref-get-ascii-bibliography))
- ((eq format 'html) (org-ref-get-html-bibliography))
- ((eq format 'latex)
- ;; write out the latex bibliography command
- (format "\\bibliography{%s}" (replace-regexp-in-string "\\.bib" "" (mapconcat 'identity
- (mapcar 'expand-file-name
- (split-string keyword ","))
- ",")))))))
-
-#+END_SRC
-
-Believe it or not, sometimes it makes sense /not/ to include the bibliography in a document (e.g. when you are required to submit references as a separate file). To generate the references, in another file, you must make a little tex file with these contents, and then compile it.
-
-#+BEGIN_LaTeX
- \input{project-description.bbl}
-#+END_LaTeX
-
-Here, we make a =nobibliography= link that acts like the bibliography, enables creation of the bbl file, but does not put an actual bibliography in the file.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type "nobibliography"
- ;; this code is run on clicking. The bibliography
- ;; may contain multiple files. this code finds the
- ;; one you clicked on and opens it.
- (lambda (link-string)
- ;; get link-string boundaries
- ;; we have to go to the beginning of the line, and then search forward
-
- (let* ((bibfile)
- ;; object is the link you clicked on
- (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)))
-
- ;; We set the reftex-default-bibliography
- ;; here. it should be a local variable only in
- ;; the current buffer. We need this for using
- ;; reftex to do citations.
- (set (make-local-variable 'reftex-default-bibliography)
- (split-string (org-element-property :path object) ","))
-
- ;; 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)))
- (find-file bibfile))) ; open file on click
-
- ;; formatting code
- (lambda (keyword desc format)
- (cond
- ((eq format 'org) (org-ref-get-org-bibliography))
- ((eq format 'ascii) (org-ref-get-ascii-bibliography))
- ((eq format 'html) (org-ref-get-html-bibliography))
- ((eq format 'latex)
- ;; write out the latex bibliography command
-
-; (format "{\\setbox0\\vbox{\\bibliography{%s}}}"
-; (replace-regexp-in-string "\\.bib" "" (mapconcat 'identity
-; (mapcar 'expand-file-name
-; (split-string keyword ","))
-; ",")))
-
- (format "\\nobibliography{%s}"
- (replace-regexp-in-string "\\.bib" "" (mapconcat 'identity
- (mapcar 'expand-file-name
- (split-string keyword ","))
- ",")))
-
- ))))
-#+END_SRC
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type "printbibliography"
- (lambda (arg) (message "Nothing implemented for clicking here."))
- (lambda (keyword desc format)
- (cond
- ((eq format 'org) (org-ref-get-org-bibliography))
- ((eq format 'html) (org-ref-get-html-bibliography))
- ((eq format 'latex)
- ;; write out the biblatex bibliography command
- "\\printbibliography"))
-))
-#+END_SRC
-
-We also create a bibliographystyle link. There is nothing to do on clicking here, and we create it for consistency. This sets the style for latex export, so use something appropriate there, e.g. unsrt, plain, plainnat, ...
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type "bibliographystyle"
- (lambda (arg) (message "Nothing implemented for clicking here."))
- (lambda (keyword desc format)
- (cond
- ((eq format 'latex)
- ;; write out the latex bibliography command
- (format "\\bibliographystyle{%s}" keyword)))))
-#+END_SRC
-
-*** Completion for bibliography link
-It would be nice
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-bibliography-complete-link (&optional arg)
- (format "bibliography:%s" (read-file-name "enter file: " nil nil t)))
-
-(defun org-ref-insert-bibliography-link ()
- "insert a bibliography with completion"
- (interactive)
- (insert (org-bibliography-complete-link)))
-#+END_SRC
-
-** addbibresource
-This is apparently used for biblatex.
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type "addbibresource"
- ;; this code is run on clicking. The addbibresource
- ;; may contain multiple files. this code finds the
- ;; one you clicked on and opens it.
- (lambda (link-string)
- ;; get link-string boundaries
- ;; we have to go to the beginning of the line, and then search forward
-
- (let* ((bibfile)
- ;; object is the link you clicked on
- (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)))
-
- ;; We set the reftex-default-addbibresource
- ;; here. it should be a local variable only in
- ;; the current buffer. We need this for using
- ;; reftex to do citations.
- (set (make-local-variable 'reftex-default-addbibresource)
- (split-string (org-element-property :path object) ","))
-
- ;; 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)))
- (find-file bibfile))) ; open file on click
-
- ;; formatting code
- (lambda (keyword desc format)
- (cond
- ((eq format 'html) (format "")); no output for html
- ((eq format 'latex)
- ;; write out the latex addbibresource command
- (format "\\addbibresource{%s}" keyword)))))
-#+END_SRC
-
-** List of Figures
-
-In long documents, a list of figures is not uncommon. Here we create a clickable link that generates a temporary buffer containing a list of figures in the document, and their captions. We make a function that can be called interactively, and define a link type that is rendered in LaTeX to create the list of figures.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-list-of-figures (&optional arg)
- "Generate buffer with list of figures in them"
- (interactive)
- (save-excursion (widen)
- (let* ((c-b (buffer-name))
- (counter 0)
- (list-of-figures
- (org-element-map (org-element-parse-buffer) 'link
- (lambda (link)
- "create a link for to the figure"
- (when
- (and (string= (org-element-property :type link) "file")
- (string-match-p
- "[^.]*\\.\\(png\\|jpg\\|eps\\|pdf\\)$"
- (org-element-property :path link)))
- (incf counter)
-
- (let* ((start (org-element-property :begin link))
- (parent (car (cdr (org-element-property :parent link))))
- (caption (caaar (plist-get parent :caption)))
- (name (plist-get parent :name)))
- (if caption
- (format
- "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]] %s\n"
- c-b start counter (or name "") caption)
- (format
- "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][figure %s: %s]]\n"
- c-b start counter (or name "")))))))))
- (switch-to-buffer "*List of Figures*")
- (setq buffer-read-only nil)
- (org-mode)
- (erase-buffer)
- (insert (mapconcat 'identity list-of-figures ""))
- (setq buffer-read-only t)
- (use-local-map (copy-keymap org-mode-map))
- (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
-
-(org-add-link-type
- "list-of-figures"
- 'org-ref-list-of-figures ; on click
- (lambda (keyword desc format)
- (cond
- ((eq format 'latex)
- (format "\\listoffigures")))))
-#+END_SRC
-
-** List of Tables
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-list-of-tables (&optional arg)
- "Generate a buffer with a list of tables"
- (interactive)
- (save-excursion
- (widen)
- (let* ((c-b (buffer-name))
- (counter 0)
- (list-of-tables
- (org-element-map (org-element-parse-buffer 'element) 'table
- (lambda (table)
- "create a link for to the table"
- (incf counter)
- (let ((start (org-element-property :begin table))
- (name (org-element-property :name table))
- (caption (caaar (org-element-property :caption table))))
- (if caption
- (format
- "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]] %s\n"
- c-b start counter (or name "") caption)
- (format
- "[[elisp:(progn (switch-to-buffer \"%s\")(widen)(goto-char %s))][table %s: %s]]\n"
- c-b start counter (or name ""))))))))
- (switch-to-buffer "*List of Tables*")
- (setq buffer-read-only nil)
- (org-mode)
- (erase-buffer)
- (insert (mapconcat 'identity list-of-tables ""))
- (setq buffer-read-only t)
- (use-local-map (copy-keymap org-mode-map))
- (local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
-
-(org-add-link-type
- "list-of-tables"
- 'org-ref-list-of-tables
- (lambda (keyword desc format)
- (cond
- ((eq format 'latex)
- (format "\\listoftables")))))
-#+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
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-
-(defun org-ref-count-labels (label)
- (+ (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)))
-
-(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" (org-ref-count-labels label))))
- (lambda (keyword desc format)
- (cond
- ((eq format 'html) (format "(<label>%s</label>)" path))
- ((eq format 'latex)
- (format "\\label{%s}" keyword)))))
-#+END_SRC
-
-We want to store links on labels, so you can put the cursor on the label, press C-c l, and later use C-c C-l to insert a link to the label. We also want to store links to tables with a table name, and for sections with CUSTOM_ID.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-label-store-link ()
- "store a link to a label. The output will be a ref to that label"
- ;; First we have to make sure we are on a label link.
- (let* ((object (org-element-context)))
- (when (and (equal (org-element-type object) 'link)
- (equal (org-element-property :type object) "label"))
- (org-store-link-props
- :type "ref"
- :link (concat "ref:" (org-element-property :path object))))
-
- ;; Store link on table
- (when (equal (org-element-type object) 'table)
- (org-store-link-props
- :type "ref"
- :link (concat "ref:" (org-element-property :name object))))
-
-;; it turns out this does not work. you can already store a link to a heading with a CUSTOM_ID
- ;; store link on heading with custom_id
-; (when (and (equal (org-element-type object) 'headline)
-; (org-entry-get (point) "CUSTOM_ID"))
-; (org-store-link-props
-; :type "ref"
-; :link (concat "ref:" (org-entry-get (point) "CUSTOM_ID"))))
-
- ;; and to #+label: lines
- (when (and (equal (org-element-type object) 'paragraph)
- (org-element-property :name object))
- (org-store-link-props
- :type "ref"
- :link (concat "ref:" (org-element-property :name object))))
-))
-
-(add-hook 'org-store-link-functions 'org-label-store-link)
-#+END_SRC
-** ref
-
-The ref link allows you make links to labels. Clicking on the link takes you to the label, and provides a mark to go back to.
-
-At the moment, ref links are not usable for section links. You need [[#CUSTOM_ID]] type links.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(org-add-link-type
- "ref"
- (lambda (label)
- "on clicking goto the label. Navigate back with C-c &"
- (org-mark-ring-push)
- ;; next search from beginning of the buffer
-
- ;; it is possible you would not find the label if narrowing is in effect
- (widen)
-
- (unless
- (or
- ;; our label links
- (progn
- (goto-char (point-min))
- (re-search-forward (format "label:%s\\b" label) nil t))
-
- ;; a latex label
- (progn
- (goto-char (point-min))
- (re-search-forward (format "\\label{%s}" label) nil t))
-
- ;; #+label: name org-definition
- (progn
- (goto-char (point-min))
- (re-search-forward (format "^#\\+label:\\s-*\\(%s\\)\\b" label) nil t))
-
- ;; org tblname
- (progn
- (goto-char (point-min))
- (re-search-forward (format "^#\\+tblname:\\s-*\\(%s\\)\\b" label) nil t))
-
-;; Commented out because these ref links do not actually translate correctly in LaTeX.
-;; you need [[#label]] links.
- ;; CUSTOM_ID
-; (progn
-; (goto-char (point-min))
-; (re-search-forward (format ":CUSTOM_ID:\s-*\\(%s\\)" label) nil t))
- )
- ;; we did not find anything, so go back to where we came
- (org-mark-ring-goto)
- (error "%s not found" label))
- (org-show-entry)
- (message "go back with (org-mark-ring-goto) `C-c &`"))
- ;formatting
- (lambda (keyword desc format)
- (cond
- ((eq format 'html) (format "(<ref>%s</ref>)" path))
- ((eq format 'latex)
- (format "\\ref{%s}" keyword)))))
-#+END_SRC
-
-It would be nice to use completion to enter a ref link, where a list of labels is provided. The following code searches the buffer for org and latex labels, custom_ids, and table names as potential items to make a ref link to.
-
-#+BEGIN_SRC emacs-lisp :tangle org-ref.el
-(defun org-ref-get-org-labels ()
- "find #+LABEL: labels"
- (save-excursion
- (goto-char (point-min))
- (let ((matches '()))
- (while (re-search-forward "^#\\+label:\\s-+\\(.*\\)\\b" (point-max) t)
- (add-to-list 'matches (match-string-no-properties 1) t))
-matches)))
-#+END_SRC