305 lines
9.6 KiB
EmacsLisp
305 lines
9.6 KiB
EmacsLisp
;;; org-ref-misc-links.el --- Miscellaneous links -*- lexical-binding: t; -*-
|
|
;;
|
|
;; Copyright (C) 2021 John Kitchin
|
|
|
|
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
|
|
;; Keywords: convenience
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
;;
|
|
;; * Miscellaneous links
|
|
|
|
|
|
;;; Commentary:
|
|
;;
|
|
|
|
;;; Code:
|
|
|
|
;;** List of figures
|
|
|
|
;;;###autoload
|
|
(defun org-ref-list-of-figures (&optional _arg)
|
|
"Generate buffer with list of figures in them.
|
|
ARG does nothing.
|
|
Ignore figures in COMMENTED sections."
|
|
(interactive)
|
|
(save-excursion
|
|
(widen)
|
|
(let* ((c-b (buffer-name))
|
|
(counter 0)
|
|
(list-of-figures
|
|
(org-element-map (org-ref-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\\|svg\\)$"
|
|
(org-element-property :path link))
|
|
;; ignore commented sections
|
|
(save-excursion
|
|
(goto-char (org-element-property :begin link))
|
|
(not (or (org-in-commented-heading-p)
|
|
(org-at-comment-p)
|
|
(-intersection (org-get-tags) org-export-exclude-tags)))))
|
|
(cl-incf counter)
|
|
|
|
(let* ((start (org-element-property :begin link))
|
|
(linenum (progn (goto-char start) (line-number-at-pos)))
|
|
(fname (org-element-property :path link))
|
|
(parent (car (cdr
|
|
(org-element-property :parent link))))
|
|
(caption (cl-caaar (plist-get parent :caption)))
|
|
(name (plist-get parent :name)))
|
|
|
|
(if caption
|
|
(format "[[file:%s::%s][Figure %s:]] %s\n" c-b linenum counter caption)
|
|
;; if it has no caption, try the name
|
|
;; if it has no name, use the file name
|
|
(cond (name
|
|
(format "[[file:%s::%s][Figure %s:]] %s\n" c-b linenum counter name))
|
|
(fname
|
|
(format "[[file:%s::%s][Figure %s:]] %s\n"
|
|
c-b linenum counter fname))))))))))
|
|
(switch-to-buffer "*List of Figures*")
|
|
(setq buffer-read-only nil)
|
|
(org-mode)
|
|
(erase-buffer)
|
|
(insert (mapconcat 'identity list-of-figures ""))
|
|
(goto-char (point-min))
|
|
;; open links in the same window
|
|
(setq-local org-link-frame-setup
|
|
'((file . find-file)))
|
|
(setq buffer-read-only t)
|
|
(use-local-map (copy-keymap org-mode-map))
|
|
(local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
|
|
|
|
|
|
(org-link-set-parameters "list-of-figures"
|
|
:follow #'org-ref-list-of-figures
|
|
:export (lambda (_path _desc format)
|
|
(cond
|
|
((eq format 'latex)
|
|
(format "\\listoffigures")))))
|
|
|
|
;;** List of tables
|
|
;;;###autoload
|
|
(defun org-ref-list-of-tables (&optional _arg)
|
|
"Generate a buffer with a list of tables.
|
|
ARG does nothing."
|
|
(interactive)
|
|
(save-excursion
|
|
(widen)
|
|
(let* ((c-b (buffer-name))
|
|
(counter 0)
|
|
(list-of-tables
|
|
(org-element-map (org-ref-parse-buffer 'element) 'table
|
|
(lambda (table)
|
|
"create a link for to the table"
|
|
(save-excursion
|
|
(goto-char (org-element-property :begin table))
|
|
(when
|
|
;; ignore commented sections
|
|
(not (or (org-in-commented-heading-p)
|
|
(-intersection (org-get-tags) org-export-exclude-tags)
|
|
(looking-at "#\\+RESULTS:") ))
|
|
(cl-incf counter)
|
|
(let* ((start (org-element-property :begin table))
|
|
(linenum (progn (goto-char start) (line-number-at-pos)))
|
|
(caption (cl-caaar (org-element-property :caption table)))
|
|
(name (org-element-property :name table)))
|
|
(if caption
|
|
(format "[[file:%s::%s][Table %s:]] %s\n" c-b linenum counter caption)
|
|
;; if it has no caption, try the name
|
|
;; if it has no name, use generic name
|
|
(cond (name
|
|
(format "[[file:%s::%s][Table %s:]] %s\n"
|
|
c-b linenum counter name))
|
|
(t
|
|
(format "[[file:%s::%s][Table %s:]] No caption\n"
|
|
c-b linenum counter)))))))))))
|
|
(switch-to-buffer "*List of Tables*")
|
|
(setq buffer-read-only nil)
|
|
(org-mode)
|
|
(erase-buffer)
|
|
(insert (mapconcat 'identity list-of-tables ""))
|
|
(goto-char (point-min))
|
|
;; open links in the same window
|
|
(setq-local org-link-frame-setup
|
|
'((file . find-file)))
|
|
(setq buffer-read-only t)
|
|
(use-local-map (copy-keymap org-mode-map))
|
|
(local-set-key "q" #'(lambda () (interactive) (kill-buffer))))))
|
|
|
|
|
|
(org-link-set-parameters "list-of-tables"
|
|
:follow #'org-ref-list-of-tables
|
|
:export (lambda (_path _desc format)
|
|
(cond
|
|
((eq format 'latex)
|
|
(format "\\listoftables")))))
|
|
|
|
|
|
;;* Index link
|
|
;;
|
|
;; You need these lines in the header
|
|
;;
|
|
;; #+latex_header: \usepackage{makeidx}
|
|
;; #+latex_header: \makeindex
|
|
(org-link-set-parameters "index"
|
|
:follow (lambda (path)
|
|
(occur path))
|
|
:export (lambda (path _desc format)
|
|
(cond
|
|
((eq format 'latex)
|
|
(format "\\index{%s}" path)))))
|
|
|
|
|
|
;; this will generate a temporary index of entries in the file when clicked on.
|
|
;;;###autoload
|
|
(defun org-ref-index (&optional _path)
|
|
"Open an *index* buffer with links to index entries.
|
|
PATH is required for the org-link, but it does nothing here."
|
|
(interactive)
|
|
(let ((*index-links* '())
|
|
(*initial-letters* '()))
|
|
|
|
;; get links
|
|
(org-element-map (org-ref-parse-buffer) 'link
|
|
(lambda (link)
|
|
(let ((plist (nth 1 link)))
|
|
|
|
(when (equal (plist-get plist ':type) "index")
|
|
(add-to-list
|
|
'*index-links*
|
|
(cons (plist-get plist :path)
|
|
(format
|
|
"[[elisp:(progn (switch-to-buffer \"%s\") (goto-char %s) (org-cycle '(64)))][%s]] "
|
|
(current-buffer)
|
|
(plist-get plist :begin) ;; position of link
|
|
;; grab a description
|
|
(save-excursion
|
|
(goto-char (plist-get plist :begin))
|
|
(if (thing-at-point 'sentence)
|
|
;; get a sentence
|
|
(let ((s (thing-at-point 'sentence)))
|
|
(cl-loop for char in '("[" "]" "\n")
|
|
do
|
|
(setq s (replace-regexp-in-string
|
|
(regexp-quote char) " " s)))
|
|
(concat s " "))
|
|
;; or call it a link
|
|
"link")))))))))
|
|
|
|
;; sort the links
|
|
(setq *index-links* (cl-sort *index-links* 'string-lessp :key 'car))
|
|
|
|
;; now separate out into chunks first letters
|
|
(dolist (link *index-links*)
|
|
(push (substring (car link) 0 1) *initial-letters*))
|
|
|
|
(setq *initial-letters* (reverse *initial-letters*))
|
|
|
|
;; now create the index
|
|
(switch-to-buffer (get-buffer-create "*index*"))
|
|
(org-mode)
|
|
(erase-buffer)
|
|
(insert "#+TITLE: Index\n\n")
|
|
(dolist (letter *initial-letters*)
|
|
(insert (format "* %s\n" (upcase letter)))
|
|
;; now process the links
|
|
(while (and
|
|
*index-links*
|
|
(string= letter (substring (car (car *index-links*)) 0 1)))
|
|
(let ((link (pop *index-links*)))
|
|
(insert (format "%s %s\n\n" (car link) (cdr link))))))
|
|
(switch-to-buffer "*index*")))
|
|
|
|
|
|
(org-link-set-parameters "printindex"
|
|
:follow #'org-ref-index
|
|
:export (lambda (_path _desc format)
|
|
(cond
|
|
((eq format 'latex)
|
|
(format "\\printindex")))))
|
|
|
|
|
|
(defun org-ref-idxproc (_backend)
|
|
"Preprocess index entries.
|
|
Each entry is replaced by a radio target. The printindex is
|
|
replaced by links to them."
|
|
(let* ((index-links (reverse (org-element-map (org-element-parse-buffer) 'link
|
|
(lambda (lnk)
|
|
(when (string= "index" (org-element-property :type lnk))
|
|
lnk)))))
|
|
(sorted-groups (seq-sort-by
|
|
(lambda (x)
|
|
"Alphabetically sort groups"
|
|
(car x))
|
|
#'string-lessp
|
|
(seq-group-by
|
|
(lambda (lnk)
|
|
(org-element-property :path lnk))
|
|
index-links)))
|
|
(link-replacements '()))
|
|
|
|
;; Sort within each group
|
|
(cl-loop for (key . links) in sorted-groups do
|
|
(setf (cdr (assoc key sorted-groups))
|
|
(sort links (lambda (a b)
|
|
(< (org-element-property :begin a)
|
|
(org-element-property :begin b))))))
|
|
|
|
;; Compute replacements for each index link.
|
|
(cl-loop for (key . links) in sorted-groups do
|
|
(cl-loop for i from 0 for lnk in links do
|
|
(cl-pushnew (cons
|
|
(org-element-property :begin lnk)
|
|
(format "<<%s-%s>>" key i))
|
|
link-replacements)))
|
|
|
|
(cl-loop for il in index-links collect
|
|
(setf (buffer-substring (org-element-property :begin il)
|
|
(org-element-property :end il))
|
|
(cdr (assoc (org-element-property :begin il) link-replacements))))
|
|
|
|
;; Now we replace the printindex link
|
|
(org-element-map (org-element-parse-buffer) 'link
|
|
(lambda (lnk)
|
|
(when (string= "printindex" (org-element-property :type lnk))
|
|
(setf (buffer-substring (org-element-property :begin lnk)
|
|
(org-element-property :end lnk))
|
|
;; If sorted-groups is empty, we should do nothing I think.
|
|
(if sorted-groups
|
|
(format "*Index*\n\n%s"
|
|
(string-join
|
|
(cl-loop for (key . links) in sorted-groups collect
|
|
(format "%s: %s"
|
|
key
|
|
(string-join
|
|
(cl-loop for i from 0 for lnk in links collect
|
|
(format "[[%s-%s][%s-%s]] "
|
|
(org-element-property :path lnk)
|
|
i
|
|
(org-element-property :path lnk)
|
|
i))
|
|
", ")))
|
|
"\n\n"))
|
|
"")))))))
|
|
|
|
|
|
(provide 'org-ref-misc-links)
|
|
|
|
;;; org-ref-misc-links.el ends here
|