2 ;;; org-show.el --- Summary
3 ;; Copyright(C) 2014 John Kitchin
5 ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
6 ;; Contributions from Sacha Chua.
7 ;; This file is not currently part of GNU Emacs.
9 ;; This program is free software; you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License as
11 ;; published by the Free Software Foundation; either version 2, or (at
12 ;; your option) any later version.
14 ;; This program is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program ; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
25 ;; A simple mode for presenting org-files as slide-shows
27 (defvar org-show-presentation-file nil "File containing the presentation.")
28 (defvar org-show-slide-tag "slide" "Tag that marks slides.")
29 (defvar org-show-slide-tag-regexp (concat ":" (regexp-quote org-show-slide-tag) ":"))
30 (defvar org-show-latex-scale 4.0 "scale for latex preview")
32 (defvar org-show-original-latex-scale
33 (plist-get org-format-latex-options :scale)
34 "Original scale for latex preview, so we can reset it.")
36 (defvar org-show-text-scale 4 "scale for text in presentation")
37 (defvar org-show-current-slide-number 1 "holds current slide number")
39 (defvar org-show-mogrify-p (executable-find "mogrify"))
41 (defvar org-show-tags-column -60 "column position to move tags to in slide mode")
42 (defvar org-show-original-tags-column org-tags-column "Save value so we can change back to it")
44 (when org-show-mogrify-p (require 'eimp))
48 (defvar org-show-mode-map
49 (let ((map (make-sparse-keymap)))
50 (define-key map [next] 'org-show-next-slide)
51 (define-key map [prior] 'org-show-previous-slide)
53 (define-key map [f5] 'org-show-start-slideshow)
54 (define-key map [f6] 'org-show-execute-slide)
55 (define-key map (kbd "C--") 'org-show-decrease-text-size)
56 (define-key map (kbd "C-=") 'org-show-increase-text-size)
57 (define-key map (kbd "\e\eg") 'org-show-goto-slide)
58 (define-key map (kbd "\e\et") 'org-show-toc)
59 (define-key map (kbd "\e\eq") 'org-show-stop-slideshow)
61 "Keymap for org-show-mode.")
63 (easy-menu-define my-menu org-show-mode-map "My own menu"
65 ["Start slide show" org-show-start-slideshow t]
66 ["Next slide" org-show-next-slide t]
67 ["Previous slide" org-show-previous-slide t]
68 ["Open this slide" org-show-open-slide t]
69 ["Goto slide" org-show-goto-slide t]
70 ["Table of contents" org-show-toc t]
71 ["Stop slide show" org-show-stop-slideshow t]
75 (define-minor-mode org-show-mode
76 "Minor mode for org-show
78 \\{org-show-mode-map}"
81 :keymap org-show-mode-map)
83 (defvar org-show-temp-images '() "list of temporary images")
85 (defun org-show-execute-slide ()
86 "Process slide at point.
87 If it contains an Emacs Lisp source block, evaluate it.
88 If it contains an image, view it in a split buffer
89 Else, focus on that buffer.
92 (setq org-show-presentation-file (expand-file-name (buffer-name)))
93 (delete-other-windows)
95 ;; make sure nothing is folded. This seems to be necessary to
96 ;; prevent an error on narrowing then trying to make latex fragments
100 (org-narrow-to-subtree)
102 (let ((heading-text (nth 4 (org-heading-components)))
103 (org-format-latex-options (plist-put org-format-latex-options :scale org-show-latex-scale)))
105 (set-frame-name (format "%-180s%15s%s" heading-text "slide " (cdr (assoc heading-text org-show-slide-titles))))
107 ;; preview equations in the current subtree
108 (org-preview-latex-fragment '(4))
109 (message "") ; clear minibuffer
112 ;; view images if there is one. WE only do this this for the first one.
113 ((and (goto-char (point-min))
114 (re-search-forward "\\[\\[\\(.*\\.\\(jpg\\|gif\\|png\\)\\)" nil t))
116 (unless (file-exists-p "org-show-images")
117 (make-directory "org-show-images"))
119 (let* ((png-file (match-string 1))
120 (temp-png (expand-file-name (concat "org-show-images/" (secure-hash 'sha1
122 (insert-file-contents png-file)
123 (buffer-string))) ".png"))))
125 (add-to-list 'org-show-temp-images temp-png)
126 (unless (file-exists-p temp-png)
127 (copy-file png-file temp-png t))
133 (when org-show-mogrify-p
134 (eimp-fit-image-width-to-window nil)))
136 (other-window 1) ; back to slide
137 (goto-char (point-min))
138 (text-scale-set org-show-text-scale)
139 (org-display-inline-images)
140 (org-cycle-hide-drawers t)
143 ;; find and execute source code blocks.
144 ;; you can either have images, or code. Not both.
145 ;; Only code blocks of type emacs-lisp-slide are used.
146 ((and (goto-char (point-min))
147 (re-search-forward "#\\+begin_src emacs-lisp-slide" nil t))
148 (let ((info (org-babel-get-src-block-info)))
150 (eval (read (concat "(progn " (nth 1 info) ")"))))))
154 (switch-to-buffer (current-buffer))
155 (text-scale-set org-show-text-scale)
157 (org-cycle-hide-drawers t)
158 (org-display-inline-images)
159 (delete-other-windows)))))
161 (defun org-show-next-slide ()
162 "Goto next slide in presentation"
164 (find-file org-show-presentation-file)
166 (if (<= (+ org-show-current-slide-number 1) (length org-show-slide-titles))
168 (setq org-show-current-slide-number (+ org-show-current-slide-number 1))
169 (org-show-goto-slide org-show-current-slide-number))
170 (org-show-goto-slide org-show-current-slide-number)
171 (message "This is the end. My only friend the end. Jim Morrison.")))
173 (defun org-show-previous-slide ()
174 "Goto previous slide in the list"
176 (find-file org-show-presentation-file)
178 (if (> (- org-show-current-slide-number 1) 0)
180 (setq org-show-current-slide-number (- org-show-current-slide-number 1))
181 (org-show-goto-slide org-show-current-slide-number))
182 (org-show-goto-slide org-show-current-slide-number)
183 (message "Once upon a time...")))
185 (defun org-show-open-slide ()
186 "Start show at this slide"
187 (setq org-show-presentation-file (expand-file-name (buffer-name)))
188 (org-show-initialize)
189 (let ((n (cdr (assoc (nth 4 (org-heading-components)) org-show-slide-titles))))
190 (setq org-show-current-slide-number n)
191 (org-show-goto-slide n)))
193 (defvar org-show-slide-list '() "List of slide numbers and markers to each slide")
194 (defvar org-show-slide-titles '() "List of titles and slide numbers for each slide")
196 (defun org-show-initialize ()
197 ;; make slide lists for future navigation. rerun this if you change slide order
198 (setq org-show-slide-titles '()
199 org-show-temp-images '()
200 org-show-slide-list '())
205 (when (string-match-p ":slide:" (or (nth 5 (org-heading-components)) ""))
208 (add-to-list 'org-show-slide-titles
209 (cons (nth 4 (org-heading-components)) n) t)
211 (add-to-list 'org-show-slide-list
212 (cons n (set-marker (make-marker) (point))) t))))))
214 (defun org-show-start-slideshow ()
215 "Start the slide show, at the beginning"
218 (setq org-show-presentation-file (expand-file-name (buffer-name)))
219 (beginning-of-buffer)
220 (setq org-tags-column org-show-tags-column)
221 (org-set-tags-command '(4) t)
223 (org-show-initialize)
226 (while (re-search-forward ":slide:" nil t)
228 (make-overlay (match-beginning 0)(match-end 0))
230 (add-to-invisibility-spec 'slide)
231 (beginning-of-buffer)
232 (delete-other-windows)
234 (setq org-show-current-slide-number 1)
235 (org-show-goto-slide 1))
237 (defun org-show-stop-slideshow ()
239 ;; make slide tag visible again
240 (remove-from-invisibility-spec 'slide)
243 (plist-put org-format-latex-options :scale org-show-original-latex-scale)
245 ;; clean up temp images
247 (let ((bname (file-name-nondirectory x)))
248 (when (get-buffer bname)
251 (kill-buffer bname)))
253 (when (file-exists-p x)
255 org-show-temp-images)
256 (setq org-show-temp-images '())
258 ;; ;; clean up miscellaneous buffers
259 (when (get-buffer "*Animation*") (kill-buffer "*Animation*"))
261 (when org-show-presentation-file (find-file org-show-presentation-file))
264 (delete-other-windows)
265 (setq org-show-presentation-file nil)
266 (setq org-show-current-slide-number 1)
267 (set-frame-name (if (buffer-file-name)
268 (abbreviate-file-name (buffer-file-name))))
269 (setq org-tags-column org-show-original-tags-column)
270 (org-set-tags-command '(4) t)
274 (defalias 'stop 'org-show-stop-slideshow)
276 (defun org-show-goto-slide (n)
278 (interactive "nSlide number: ")
279 (message "Going to slide %s" n)
280 (find-file org-show-presentation-file)
281 (setq org-show-current-slide-number n)
283 (goto-char (cdr (assoc n org-show-slide-list)))
284 (org-show-execute-slide))
286 (defun org-show-toc ()
288 (let ((links) (c-b (buffer-name)) (n))
297 (format " [[elisp:(progn (switch-to-buffer \"%s\")(goto-char %s)(org-show-execute-slide))][%2s %s]]\n\n"
298 (marker-buffer (cdr x))
299 (marker-position (cdr x))
301 (nth 4 (org-heading-components))) t))
302 org-show-slide-list))
304 (switch-to-buffer "*List of Slides*")
308 (insert (mapconcat 'identity links ""))
310 ;(setq buffer-read-only t)
311 (use-local-map (copy-keymap org-mode-map))
312 (local-set-key "q" #'(lambda () (interactive) (kill-buffer)))))
316 (defun org-show-animate (strings)
317 "Animate STRINGS in an *Animation* buffer"
318 (switch-to-buffer (get-buffer-create
319 (or animation-buffer-name
323 (let* ((vpos (/ (- 20
324 1 ;; For the mode-line
325 (1- (length strings))
331 (setq hpos (/ (- width (length (car strings))) 2))
332 (when (> 0 hpos) (setq hpos 0))
333 (when (> 0 vpos) (setq vpos 0))
334 (animate-string (car strings) vpos hpos)
335 (setq vpos (1+ vpos))
336 (setq strings (cdr strings)))))
338 (defun org-show-increase-text-size (&optional arg)
339 "Increase text size. Bound to \\[org-show-increase-text-size].
341 With prefix ARG, set `org-show-text-scale' so subsquent slides are the same text size."
343 (text-scale-increase 1.5)
345 (setq org-show-text-scale (* org-show-text-scale 1.5))))
347 (defun org-show-decrease-text-size (&optional arg)
348 "Increase text size. Bound to \\[org-show-decrease-text-size].
350 With prefix ARG, set `org-show-text-scale' so subsquent slides are the same text size."
352 (text-scale-decrease 1.5)
354 (setq org-show-text-scale (/ org-show-text-scale 1.5)))