add org directory
[org-ref.git] / org-show.org
1 #+TITLE: org-show - simple presentations in org-mode
2 #+AUTHOR: John Kitchin
3
4 There are several options for "presenting" from org-mode. Here are the options I found.
5
6 https://github.com/rlister/org-present
7 https://github.com/eschulte/epresent
8
9 https://github.com/yjwen/org-reveal
10 https://github.com/takaxp/org-tree-slide/
11 https://github.com/tucasp/org-presie
12
13 http://orgmode.org/worg/exporters/beamer/tutorial.html
14 http://orgmode.org/worg/org-tutorials/non-beamer-presentations.html#sec-3
15
16 The one I like the best is discussed here: http://sachachua.com/blog/2013/04/how-to-present-using-org-mode-in-emacs/. I like it best because you can edit the slides as you go, execute arbitrary emacs code, and it is still pretty simple. I used Sacha's code as the basis for org-show. There is a lot of similarity.
17
18 elisp:org-show-mode
19
20 elisp:org-show-start-slideshow
21
22 * org-show
23 You can have: 
24
25 1. code run
26 2. split to show slide and full image
27 3. plain text
28
29 ** Title slide                                                        :slide:
30 #+BEGIN_SRC emacs-lisp-slide
31 (org-show-animate '("Welcome to the org-show" "John Kitchin"))
32 #+END_SRC
33
34 ** Presentations in org-mode                                          :slide:
35 This should be easy
36
37 1. Create your org-file. Tag headlines with :slide:
38 2. Enter org-show-mode, press f5. Use PageUp and PageDn to navigate slides
39 3. Go back and forth from the presentation to other files in Emacs or other software.
40 4. Edit yours slides as you go, e.g. to demonstrate something 
41 5. Totally interactive, run code, etc...
42
43 org-show is based on this blog post: http://sachachua.com/blog/2013/04/how-to-present-using-org-mode-in-emacs/
44
45 Thanks Sacha!
46 ** Test out some themes                                               :slide:
47
48 [[elisp:(load-theme 'my)]] [[elisp:(disable-theme 'my)]]
49
50 [[elisp:(load-theme 'adwaita)]] [[elisp:(disable-theme 'adwaita)]]
51
52 [[elisp:(load-theme 'deeper-blue)]] [[elisp:(disable-theme 'deeper-blue)]]
53
54 [[elisp:(load-theme 'light-blue)]] [[elisp:(disable-theme 'light-blue)]]
55
56 [[elisp:(load-theme 'manoj-dark)]] [[elisp:(disable-theme 'manoj-dark)]]
57
58 [[elisp:(load-theme 'misterioso)]] [[elisp:(disable-theme 'misterioso)]]
59
60 [[elisp:(load-theme 'tango)]] [[elisp:(disable-theme 'tango)]]
61
62 [[elisp:(load-theme 'tango-dark)]] [[elisp:(disable-theme 'tango-dark)]]
63
64 [[elisp:(load-theme 'tsdh-dark)]] [[elisp:(disable-theme 'tsdh-dark)]]
65
66 [[elisp:(load-theme 'tsdh-light)]] [[elisp:(disable-theme 'tsdh-light)]]
67
68 [[elisp:(load-theme 'wheatgrass)]] [[elisp:(disable-theme 'wheatgrass)]]
69
70 [[elisp:(load-theme 'whiteboard)]] [[elisp:(disable-theme 'whiteboard)]]
71
72 [[elisp:(load-theme 'wombat)]] [[elisp:(disable-theme 'wombat)]]
73
74 [[elisp:(load-theme 'solarized-light t)]] [[elisp:(disable-theme 'solarized-light)]] 
75
76 [[elisp:(load-theme 'solarized-dark t)]] [[elisp:(disable-theme 'solarized-dark)]]
77
78 [[elisp:(load-theme 'zenburn t)]] [[elisp:(disable-theme 'zenburn)]]
79
80 [[elisp:(load-theme 'anti-zenburn t)]] [[elisp:(disable-theme 'anti-zenburn)]]
81
82 ** Equations                                                          :slide:
83 It should be easy to show equations like this  $\int_0^x \frac{1}{2} \sin x dx = 6$.
84
85 It is. Maybe you prefer equation environments?
86
87 \begin{equation}
88 e^x = 55
89 \end{equation}
90
91 Want to see the equation source? [[elisp:(org-ctrl-c-ctrl-c)][click here]]
92
93 Back to equations: C-c C-x C-l
94 ** Figures                                                            :slide:
95
96 Figures should show up in two panes.
97 The left pane shows the slide. The right pane shows the figure, scaled to fit in the window.
98
99 Here is a little screen capture:
100 [[./taskbar.png]]
101
102 ** Need a more complicated layout?                                    :slide:
103 Write some code to generate it, and put it in an emacs-lisp-slide block. org-show will run it and show you the result
104
105 #+BEGIN_SRC emacs-lisp
106 (delete-other-windows)
107 (split-window-right)
108 (other-window 1)
109 (find-file "taskbar.png")
110 (split-window-below)
111 (other-window 1)
112 (find-file "doi-utils.org")
113 #+END_SRC
114
115 #+RESULTS:
116 : #<buffer doi-utils.org>
117
118 #+BEGIN_EXAMPLE
119 ,#+BEGIN_SRC emacs-lisp-slide
120 (delete-other-windows)
121 (split-window-right)
122 (other-window 1)
123 (find-file "taskbar.png")
124 (split-window-below)
125 (other-window 1)
126 (find-file "doi-utils.org")
127 ,#+END_SRC
128 #+END_EXAMPLE
129
130 ** A complicated layout                                               :slide:
131 #+BEGIN_SRC emacs-lisp-slide
132 (delete-other-windows)
133 (split-window-right)
134 (other-window 1)
135 (find-file "taskbar.png")
136 (split-window-below)
137 (other-window 1)
138 (find-file "doi-utils.org")
139 #+END_SRC
140 ** Code blocks should be runnable and editable                        :slide:
141
142 #+BEGIN_SRC python
143 print 6 + 62
144 #+END_SRC
145
146
147 They are.
148 ** We can use many languages                                          :slide:
149 (of course, you must have them installed on your computer)
150
151 #+BEGIN_SRC emacs-lisp
152 (+ 6 6)
153 #+END_SRC
154
155
156 #+BEGIN_SRC R 
157 sum(c(6, 6))
158 #+END_SRC
159
160
161
162 #+BEGIN_SRC perl :results output
163 print 6 + 6
164 #+END_SRC
165
166
167 #+BEGIN_SRC ruby
168 print 6 + 6
169 #+END_SRC
170
171 #+RESULTS:
172
173
174 ** Interactivity is important   
175 We get it.
176 *** Snake                                                             :slide:
177 #+BEGIN_SRC emacs-lisp-slide
178 (snake)
179 #+END_SRC
180
181 *** tetris                                                            :slide:
182
183 #+BEGIN_SRC emacs-lisp-slide
184 (when (and (boundp 'snake-buffer-name) (get-buffer snake-buffer-name))
185   (kill-buffer snake-buffer-name))
186 (delete-other-windows)
187 (tetris)
188 #+END_SRC
189
190
191 *** doctor                                                            :slide:
192 #+BEGIN_SRC emacs-lisp-slide
193 (doctor)
194 #+END_SRC
195
196
197 *** Become a graffiti artist                                          :slide:
198 #+BEGIN_SRC emacs-lisp-slide
199 (progn
200   (switch-to-buffer (get-buffer-create "*artist*"))
201   (erase-buffer)
202   (artist-mode 1)
203   (menu-bar-mode 1)
204   (text-scale-set 0)
205   (artist-select-op-spray-can))
206 #+END_SRC
207
208
209 *** Or draw lines                                                     :slide:
210 #+BEGIN_SRC emacs-lisp-slide
211 (progn
212   (switch-to-buffer (get-buffer-create "*artist*"))
213   (artist-select-op-line))
214 #+END_SRC
215
216 ** No seriously, we can do real work!                                 :slide:
217    :PROPERTIES:
218    :CUSTOM_ID: sec:data-tab-code
219    :END:
220
221 Use this table as a data source.
222 #+tblname: tab-data
223 | x |  y |
224 |---+----|
225 | 1 |  1 |
226 | 2 |  4 |
227 | 3 |  9 |
228 | 4 | 16 |
229
230 #+BEGIN_SRC python :var data=tab-data
231 import matplotlib.pyplot as plt
232 import numpy as np
233 d = np.array(data)
234 plt.plot(d[:,0], d[:,1])
235 plt.show()
236 #+END_SRC  
237
238 #+RESULTS:
239
240 You can make links to a table like this: ref:tab-data.
241 ** Interactive links                                                  :slide:
242 <<beginning>>
243
244 You can have links that take you to places: [[beginning]], [[end]], to a [[#sec:data-tab-code][section]],
245
246 Or links that are functional: cite:mehta-2014-ident-poten. 
247
248 Or that run code [[elisp:(message "Hello %s" user-full-name)]]
249
250 Or links to info: [[info:org#External%20links][info:org#External links]]
251
252 Or to open a [[http://kitchingroup.cheme.cmu.edu][website]].
253
254 <<end>>
255 ** Conclusions                                                        :slide:
256 That is the end!
257
258 #+BEGIN_SRC emacs-lisp-slide
259 (org-show-animate '("That's the end of the org-show." "Thank you for your attention!" "http://github.com/jkitchin/jmax"))
260 #+END_SRC
261
262
263 * The code
264
265 ** The header
266
267 #+BEGIN_SRC emacs-lisp :tangle org-show.el
268 ;;; org-show.el --- Summary
269 ;; Copyright(C) 2014 John Kitchin
270
271 ;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
272 ;; Contributions from Sacha Chua.
273 ;; This file is not currently part of GNU Emacs.
274
275 ;; This program is free software; you can redistribute it and/or
276 ;; modify it under the terms of the GNU General Public License as
277 ;; published by the Free Software Foundation; either version 2, or (at
278 ;; your option) any later version.
279
280 ;; This program is distributed in the hope that it will be useful, but
281 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
282 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
283 ;; General Public License for more details.
284
285 ;; You should have received a copy of the GNU General Public License
286 ;; along with this program ; see the file COPYING.  If not, write to
287 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
288 ;; Boston, MA 02111-1307, USA.
289
290 ;;; Commentary:
291 ;; A simple mode for presenting org-files as slide-shows
292 #+END_SRC
293
294 ** Some basic setup
295 #+BEGIN_SRC emacs-lisp :tangle org-show.el
296 (defvar org-show-presentation-file nil "File containing the presentation.")
297 (defvar org-show-slide-tag "slide" "Tag that marks slides.")
298 (defvar org-show-slide-tag-regexp (concat ":" (regexp-quote org-show-slide-tag) ":"))
299 (defvar org-show-latex-scale 4.0 "scale for latex preview")
300
301 (defvar org-show-original-latex-scale
302   (plist-get org-format-latex-options :scale)
303   "Original scale for latex preview, so we can reset it.")
304
305 (defvar org-show-text-scale 4 "scale for text in presentation")
306 (defvar org-show-current-slide-number 1 "holds current slide number")
307
308 (defvar org-show-mogrify-p (executable-find "mogrify"))
309
310 (defvar org-show-tags-column -60 "column position to move tags to in slide mode")
311 (defvar org-show-original-tags-column org-tags-column "Save value so we can change back to it")
312
313 (when org-show-mogrify-p (require 'eimp))
314
315
316 #+END_SRC
317
318 ** Make a minor mode and menu
319
320 #+BEGIN_SRC emacs-lisp :tangle org-show.el
321 (require 'easymenu)
322
323 (defvar org-show-mode-map
324   (let ((map (make-sparse-keymap)))
325     (define-key map [next] 'org-show-next-slide)
326     (define-key map [prior] 'org-show-previous-slide)
327     
328     (define-key map [f5] 'org-show-start-slideshow)
329     (define-key map [f6] 'org-show-execute-slide)
330     (define-key map (kbd "C--") 'org-show-decrease-text-size)
331     (define-key map (kbd "C-=") 'org-show-increase-text-size)
332     (define-key map (kbd "\e\eg") 'org-show-goto-slide)
333     (define-key map (kbd "\e\et") 'org-show-toc)
334     (define-key map (kbd "\e\eq") 'org-show-stop-slideshow)
335     map)
336   "Keymap for org-show-mode.")
337
338 (easy-menu-define my-menu org-show-mode-map "My own menu"
339   '("org-show"
340     ["Start slide show" org-show-start-slideshow t]
341     ["Next slide" org-show-next-slide t]
342     ["Previous slide" org-show-previous-slide t]
343     ["Open this slide" org-show-open-slide t]
344     ["Goto slide" org-show-goto-slide t]
345     ["Table of contents" org-show-toc t]
346     ["Stop slide show"  org-show-stop-slideshow t]
347 ))
348
349
350 (define-minor-mode org-show-mode
351   "Minor mode for org-show
352
353 \\{org-show-mode-map}"
354   :lighter " org-show"
355   :global t
356   :keymap org-show-mode-map)
357 #+END_SRC
358
359 ** Prepare and show the slide 
360
361 #+BEGIN_SRC emacs-lisp :tangle org-show.el
362
363 (defvar org-show-temp-images '() "list of temporary images")
364
365 (defun org-show-execute-slide ()
366   "Process slide at point.
367   If it contains an Emacs Lisp source block, evaluate it.
368   If it contains an image, view it in a split buffer
369   Else, focus on that buffer.
370   Hide all drawers."
371   (interactive)
372   (setq org-show-presentation-file (expand-file-name (buffer-name)))
373   (delete-other-windows)  
374
375   ;; make sure nothing is folded. This seems to be necessary to
376   ;; prevent an error on narrowing then trying to make latex fragments
377   ;; I think.
378   (org-cycle '(64))
379
380   (org-narrow-to-subtree)
381   (visual-line-mode 1)
382   (let ((heading-text (nth 4 (org-heading-components)))
383         (org-format-latex-options (plist-put org-format-latex-options :scale org-show-latex-scale)))
384
385     (set-frame-name (format "%-180s%15s%s" heading-text "slide " (cdr (assoc heading-text org-show-slide-titles))))
386
387     ;; preview equations in the current subtree
388     (org-preview-latex-fragment '(4))
389     (message "") ; clear minibuffer
390     (cond
391
392      ;; view images if there is one. WE only do this this for the first one.
393      ((and (goto-char (point-min))
394            (re-search-forward "\\[\\[\\(.*\\.\\(jpg\\|gif\\|png\\)\\)" nil t))
395       
396       (unless (file-exists-p "org-show-images")
397         (make-directory "org-show-images"))
398       
399       (let* ((png-file (match-string 1))
400              (temp-png (expand-file-name (concat "org-show-images/" (secure-hash 'sha1
401                                             (with-temp-buffer
402                                               (insert-file-contents png-file)
403                                               (buffer-string))) ".png"))))
404
405         (add-to-list 'org-show-temp-images temp-png)
406         (unless (file-exists-p temp-png)
407           (copy-file png-file temp-png t))
408       
409         (split-window-right)      
410       
411         (other-window 1)
412         (find-file temp-png)
413         (when org-show-mogrify-p
414           (eimp-fit-image-width-to-window nil)))
415                   
416       (other-window 1) ; back to slide
417       (goto-char (point-min))
418       (text-scale-set org-show-text-scale)
419       (org-display-inline-images)
420       (org-cycle-hide-drawers t)
421       (org-show-subtree))
422
423      ;; find and execute source code blocks.
424      ;; you can either have images, or code. Not both.
425      ;; Only code blocks of type emacs-lisp-slide are used.
426      ((and (goto-char (point-min))
427            (re-search-forward "#\\+begin_src emacs-lisp-slide" nil t))
428       (let ((info (org-babel-get-src-block-info)))
429         (unwind-protect
430             (eval (read (concat "(progn " (nth 1 info) ")"))))))
431
432      ;; plain text slides
433      (t
434       (switch-to-buffer (current-buffer))
435       (text-scale-set org-show-text-scale)
436       (org-show-subtree)
437       (org-cycle-hide-drawers t)
438       (org-display-inline-images)
439       (delete-other-windows)))))
440 #+END_SRC
441
442 ** Next and previous slides
443
444 #+BEGIN_SRC emacs-lisp :tangle org-show.el
445 (defun org-show-next-slide ()
446   "Goto next slide in presentation"
447   (interactive)
448   (find-file org-show-presentation-file)
449   (widen)
450   (if (<= (+ org-show-current-slide-number 1) (length org-show-slide-titles))
451       (progn
452         (setq org-show-current-slide-number (+ org-show-current-slide-number 1))
453         (org-show-goto-slide org-show-current-slide-number))
454     (org-show-goto-slide org-show-current-slide-number)
455     (message "This is the end. My only friend the end.  Jim Morrison.")))
456 #+END_SRC
457
458 #+BEGIN_SRC emacs-lisp :tangle org-show.el
459 (defun org-show-previous-slide ()
460   "Goto previous slide in the list"
461   (interactive)
462   (find-file org-show-presentation-file)
463   (widen)
464   (if (> (- org-show-current-slide-number 1) 0)
465       (progn
466         (setq org-show-current-slide-number (- org-show-current-slide-number 1))
467         (org-show-goto-slide org-show-current-slide-number))
468     (org-show-goto-slide org-show-current-slide-number)
469     (message "Once upon a time...")))
470 #+END_SRC
471
472 ** Open this slide
473
474 #+BEGIN_SRC emacs-lisp :tangle org-show.el
475 (defun org-show-open-slide ()
476  "Start show at this slide"
477  (setq org-show-presentation-file (expand-file-name (buffer-name))) 
478  (org-show-initialize)
479  (let ((n (cdr (assoc (nth 4 (org-heading-components)) org-show-slide-titles))))
480    (setq org-show-current-slide-number n)
481    (org-show-goto-slide n)))
482 #+END_SRC
483
484 ** Starting the show
485 We need some functions for convenient starting and stopping.
486
487 On starting, we want to map the slides so we can get slide numbers for navigation and to display them on the frame. We also make the slide tags invisible. We set some temporary key bindings. These need to be global because sometimes we navigate out of the slideshow buffer, and we want page up and down to go to the next slides no matter where we are.
488
489
490 #+BEGIN_SRC emacs-lisp :tangle org-show.el
491 (defvar org-show-slide-list '() "List of slide numbers and markers to each slide")
492 (defvar org-show-slide-titles '() "List of titles and slide numbers for each slide")
493
494 (defun org-show-initialize ()
495   ;; make slide lists for future navigation. rerun this if you change slide order
496   (setq  org-show-slide-titles '()
497          org-show-temp-images '()
498          org-show-slide-list '())
499      
500   (let ((n 0))
501     (org-map-entries
502      (lambda ()
503        (when (string-match-p ":slide:" (or (nth 5 (org-heading-components)) ""))
504          (setq n (+ n 1))
505          
506          (add-to-list 'org-show-slide-titles 
507                       (cons (nth 4 (org-heading-components)) n) t)
508
509          (add-to-list 'org-show-slide-list 
510                       (cons n (set-marker (make-marker) (point))) t))))))
511
512 (defun org-show-start-slideshow ()
513   "Start the slide show, at the beginning"
514   (interactive)
515     
516   (setq org-show-presentation-file (expand-file-name (buffer-name)))
517   (beginning-of-buffer)
518   (setq org-tags-column org-show-tags-column)
519   (org-set-tags-command '(4) t)
520
521   (org-show-initialize)
522   ;; hide slide tags
523   (save-excursion
524     (while (re-search-forward ":slide:" nil t)
525       (overlay-put
526        (make-overlay (match-beginning 0)(match-end 0))
527        'invisible 'slide)))
528   (add-to-invisibility-spec 'slide)
529   (beginning-of-buffer)
530   (delete-other-windows)
531   (org-show-mode 1)
532   (setq org-show-current-slide-number 1)
533   (org-show-goto-slide 1))
534 #+END_SRC
535
536 ** Stop the show
537
538 #+BEGIN_SRC emacs-lisp :tangle org-show.el
539 (defun org-show-stop-slideshow ()
540   (interactive)
541   ;; make slide tag visible again
542   (remove-from-invisibility-spec 'slide)
543
544   ;; reset latex scale
545   (plist-put org-format-latex-options :scale org-show-original-latex-scale)
546
547   ;; clean up temp images
548   (mapcar (lambda (x)
549             (let ((bname (file-name-nondirectory x)))
550               (when (get-buffer bname)
551                 (set-buffer bname) 
552                 (save-buffer)
553                 (kill-buffer bname)))
554
555             (when (file-exists-p x)
556               (delete-file x)))
557           org-show-temp-images)
558   (setq org-show-temp-images '())
559
560   ;; ;; clean up miscellaneous buffers
561   (when (get-buffer "*Animation*") (kill-buffer "*Animation*"))
562
563   (when org-show-presentation-file (find-file org-show-presentation-file))
564   (widen)
565   (text-scale-set 0)
566   (delete-other-windows)
567   (setq org-show-presentation-file nil)
568   (setq org-show-current-slide-number 1)
569   (set-frame-name (if (buffer-file-name)
570                    (abbreviate-file-name (buffer-file-name))))
571   (setq org-tags-column org-show-original-tags-column)
572   (org-set-tags-command '(4) t)
573
574   (org-show-mode -1))
575
576 (defalias 'stop 'org-show-stop-slideshow)
577 #+END_SRC
578
579 ** Goto a slide
580 #+BEGIN_SRC emacs-lisp :tangle org-show.el
581 (defun org-show-goto-slide (n)
582  "Goto slide N"
583  (interactive "nSlide number: ")
584  (message "Going to slide %s" n)
585  (find-file org-show-presentation-file)
586  (setq org-show-current-slide-number n)
587  (widen)
588  (goto-char (cdr (assoc n org-show-slide-list)))
589  (org-show-execute-slide))
590 #+END_SRC
591
592 ** Table of contents
593 #+BEGIN_SRC emacs-lisp :tangle org-show.el
594 (defun org-show-toc ()
595   (interactive)
596   (let ((links) (c-b (buffer-name)) (n))
597     (save-excursion
598       (widen)
599       (mapcar
600        (lambda (x)
601          (setq n (car x))
602          (goto-char (cdr x))
603          (add-to-list
604           'links
605           (format " [[elisp:(progn (switch-to-buffer \"%s\")(goto-char %s)(org-show-execute-slide))][%2s %s]]\n\n"
606                   (marker-buffer (cdr x))
607                   (marker-position (cdr x))
608                   (car x)
609                   (nth 4 (org-heading-components))) t))
610               org-show-slide-list))
611     
612     (switch-to-buffer "*List of Slides*")
613     (org-mode)
614     (erase-buffer)
615     
616     (insert (mapconcat 'identity links ""))
617   
618     ;(setq buffer-read-only t)
619     (use-local-map (copy-keymap org-mode-map))
620     (local-set-key "q" #'(lambda () (interactive) (kill-buffer)))))
621 #+END_SRC
622
623 ** Utilities
624 It seems like we might animate enough to have a function
625 #+BEGIN_SRC emacs-lisp :tangle org-show.el
626 (require 'animate)
627
628 (defun org-show-animate (strings)
629   "Animate STRINGS in an *Animation* buffer"
630   (switch-to-buffer (get-buffer-create
631                      (or animation-buffer-name
632                          "*Animation*")))
633   (erase-buffer)
634   (text-scale-set 6)
635   (let* ((vpos (/ (- 20
636                      1 ;; For the mode-line
637                      (1- (length strings)) 
638                      (length strings))
639                   2))
640          (width 43)
641          hpos)
642     (while strings
643       (setq hpos (/ (- width (length (car strings))) 2))
644       (when (> 0 hpos) (setq hpos 0))
645       (when (> 0 vpos) (setq vpos 0))
646       (animate-string (car strings) vpos hpos)
647       (setq vpos (1+ vpos))
648       (setq strings (cdr strings)))))
649 #+END_SRC
650
651 dynamic rescalling of text size
652
653 #+BEGIN_SRC emacs-lisp :tangle org-show.el
654 (defun org-show-increase-text-size (&optional arg)
655   "Increase text size. Bound to \\[org-show-increase-text-size].
656
657 With prefix ARG, set `org-show-text-scale' so subsquent slides are the same text size."
658   (interactive "P")
659   (text-scale-increase 1.5)
660   (when arg
661     (setq org-show-text-scale (* org-show-text-scale 1.5))))
662
663 (defun org-show-decrease-text-size (&optional arg)
664   "Increase text size. Bound to \\[org-show-decrease-text-size].
665
666 With prefix ARG, set `org-show-text-scale' so subsquent slides are the same text size."
667   (interactive "P")
668   (text-scale-decrease 1.5)
669   (when arg
670     (setq org-show-text-scale (/ org-show-text-scale 1.5)))
671 )
672 #+END_SRC
673
674 ** End
675 #+BEGIN_SRC emacs-lisp  :tangle org-show.el
676 (provide 'org-show)
677 #+END_SRC
678 * build
679 [[elisp:(org-babel-load-file "org-show.org")]]