forked from rlister/org-present
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathorg-present.el
334 lines (299 loc) · 12 KB
/
org-present.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
;;; org-present.el --- Minimalist presentation minor-mode for Emacs org-mode.
;;
;; Copyright (C) 2012 by Ric Lister
;;
;; Author: Ric Lister
;; Version: 0.1
;; Package-Requires: ((org "7"))
;; URL: https://github.com/rlister/org-present
;;
;; This file is not part of GNU Emacs.
;;
;; 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 <https://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
;; This is meant to be an extremely minimalist presentation tool for
;; Emacs org-mode.
;;
;; Usage:
;;
;; Add the following to your emacs config:
;;
;; (add-to-list 'load-path "~/path/to/org-present")
;; (autoload 'org-present "org-present" nil t)
;;
;; (add-hook 'org-present-mode-hook
;; (lambda ()
;; (org-present-big)
;; (org-display-inline-images)))
;;
;; (add-hook 'org-present-mode-quit-hook
;; (lambda ()
;; (org-present-small)
;; (org-remove-inline-images)))
;;
;; Open an org-mode file with each slide under a top-level heading.
;; Start org-present with org-present-mode, left and right keys will move forward
;; and backward through slides. C-c C-q will quit org-present.
;;
;; This works well with hide-mode-line (http://webonastick.com/emacs-lisp/hide-mode-line.el),
;; which hides the mode-line when only one frame and buffer are open.
;;
;; If you're on a Mac you might also want to look at the fullscreen patch here:
;; http://cloud.github.com/downloads/typester/emacs/feature-fullscreen.patch
(require 'outline)
(require 'org)
(defvar org-present-mode-keymap (make-keymap) "org-present-mode keymap.")
;; left and right page keys
(define-key org-present-mode-keymap [right] 'org-present-next)
(define-key org-present-mode-keymap [left] 'org-present-prev)
(define-key org-present-mode-keymap (kbd "C-c C-=") 'org-present-big)
(define-key org-present-mode-keymap (kbd "C-c C--") 'org-present-small)
(define-key org-present-mode-keymap (kbd "C-c C-q") 'org-present-quit)
(define-key org-present-mode-keymap (kbd "C-c C-r") 'org-present-read-only)
(define-key org-present-mode-keymap (kbd "C-c C-w") 'org-present-read-write)
(define-key org-present-mode-keymap (kbd "C-c <") 'org-present-beginning)
(define-key org-present-mode-keymap (kbd "C-c >") 'org-present-end)
(define-key org-present-mode-keymap (kbd "C-c C-1") 'org-present-toggle-one-big-page)
;; how much to scale up font size
(defvar org-present-text-scale 5)
(defvar org-present-cursor-cache (or cursor-type nil)
"Holds the user set value of cursor for `org-present-read-only'")
(defvar org-present-overlays-list nil)
(defvar org-present-one-big-page nil)
(define-minor-mode org-present-mode
"Minimalist presentation minor mode for org-mode."
:init-value nil
:lighter " OP"
:keymap org-present-mode-keymap)
(make-variable-buffer-local 'org-present-mode)
(defun org-present-top ()
"Jump to current top-level heading, should be safe outside a heading."
(unless (org-at-heading-p) (outline-previous-heading))
(let ((level (org-current-level)))
(when (and level (> level 1))
(outline-up-heading (- level 1) t))))
(defun org-present-next ()
"Jump to next top-level heading."
(interactive)
(widen)
(if (org-current-level) ;inside any heading
(progn
;; (org-present-top)
(or
(outline-next-heading) ;next heading
(org-present-top))) ;if that was last, go back to top before narrow
;; else handle title page before first heading
(outline-next-heading))
(org-present-narrow)
(org-present-run-after-navigate-functions))
(defun org-present-prev ()
"Jump to previous top-level heading."
(interactive)
(if (org-current-level)
(progn
(widen)
(outline-previous-heading)))
(org-present-narrow)
(org-present-run-after-navigate-functions))
(defun org-narrow-to-heading ()
(org-narrow-to-subtree)
(save-excursion
(org-next-visible-heading 1)
(narrow-to-region (point-min) (point))))
(defun org-present-narrow ()
"Show just current page.
In a heading we narrow, else show title page (before first heading)."
(if (org-current-level)
(progn
(outline-show-all)
(org-narrow-to-heading))
;; else narrow to area before first heading
(outline-next-heading)
(narrow-to-region (point-min) (point))
(goto-char (point-min))))
(defun org-present-beginning ()
"Jump to first slide of presentation."
(interactive)
(widen)
(goto-char (point-min))
(org-present-narrow)
(org-present-run-after-navigate-functions))
(defun org-present-end ()
"Jump to last slide of presentation."
(interactive)
(widen)
(goto-char (point-max))
(org-present-top)
(org-present-narrow)
(org-present-run-after-navigate-functions))
(defun org-present-big ()
"Make font size larger."
(interactive)
(text-scale-increase 0)
(text-scale-increase org-present-text-scale)) ;MAKE THIS BUFFER-LOCAL
(defun org-present-small ()
"Change font size back to original."
(interactive)
(text-scale-increase 0))
(defun org-present-add-overlay (beginning end)
"Create a single overlay over given region and remember it."
(let ((overlay (make-overlay beginning end)))
(push overlay org-present-overlays-list)
(overlay-put overlay 'invisible 'org-present)))
(defun org-present-show-option (string)
"Returns non-nil if string is an org-mode exporter option whose value we want to show."
(save-match-data
(string-match
(regexp-opt '("title:" "author:" "date:" "email:"))
string)))
(defvar org-present-hide-stars-in-headings t
"Whether to hide the asterisk characters in headings while in presentation
mode. If you turn this off (by setting it to nil) make sure to set
`org-hide-emphasis-markers' non-nil, since currently `org-present''s algorithm
for hiding emphasis markers has a bad interaction with bullets. This combo also
makes tabs work in presentation mode as in the rest of Org mode.")
(defun org-present-caption-p ()
(interactive)
(save-excursion
(beginning-of-line)
(let ((line-contents (buffer-substring-no-properties (point) (line-end-position))))
(string-match-p (rx "#+caption") line-contents))))
(defun org-present-name-p ()
(interactive)
(save-excursion
(beginning-of-line)
(let ((line-contents (buffer-substring-no-properties (point) (line-end-position))))
(string-match-p (rx "#+name") line-contents))))
(defun org-present-add-overlays ()
"Add overlays for this mode."
(add-to-invisibility-spec '(org-present))
(save-excursion
;; hide org-mode options starting with #+
(goto-char (point-min))
(while (re-search-forward "^[[:space:]]*\\(#\\+\\)\\([^[:space:]]+\\).*" nil t)
(unless (or (org-present-caption-p)
(org-present-name-p))
(let ((end (if (org-present-show-option (match-string 2)) 2 0)))
(org-present-add-overlay (match-beginning 1) (match-end end)))))
;; TODO hide org-babel properties but keep language
;; TODO do not hide "captions" and "names"
;; hide :PROPERTIES: :END: block
(progn (goto-char (point-min))
(while (re-search-forward "^[[:space:]]*\\(:PROPERTIES:\\)\\(?:.\\|\n\\)*?\\(:END:\\).*$" nil t)
(org-present-add-overlay (match-beginning 1) (match-end 2))))
;; hide stars in headings
(if org-present-hide-stars-in-headings
(progn (goto-char (point-min))
(while (re-search-forward "^\\(*+\\)" nil t)
(org-present-add-overlay (match-beginning 1) (match-end 1)))))
;; hide emphasis/verbatim markers if not already hidden by org
(if org-hide-emphasis-markers nil
;; TODO https://github.com/rlister/org-present/issues/12
;; It would be better to reuse org's own facility for this, if possible.
;; However it is not obvious how to do this.
(progn
;; hide emphasis markers
(goto-char (point-min))
(while (re-search-forward org-emph-re nil t)
(org-present-add-overlay (match-beginning 2) (1+ (match-beginning 2)))
(org-present-add-overlay (1- (match-end 2)) (match-end 2)))
;; hide verbatim markers
(goto-char (point-min))
(while (re-search-forward org-verbatim-re nil t)
(org-present-add-overlay (match-beginning 2) (1+ (match-beginning 2)))
(org-present-add-overlay (1- (match-end 2)) (match-end 2)))))))
(defun org-present-rm-overlays ()
"Remove overlays for this mode."
(mapc #'delete-overlay org-present-overlays-list)
(remove-from-invisibility-spec '(org-present)))
(defun org-present-read-only ()
"Make buffer read-only."
(interactive)
(setq buffer-read-only t)
(setq org-present-cursor-cache cursor-type
cursor-type nil)
(define-key org-present-mode-keymap (kbd "SPC") #'org-present-next))
(defun org-present-read-write ()
"Make buffer read/write."
(interactive)
(setq buffer-read-only nil)
(define-key org-present-mode-keymap (kbd "SPC") 'self-insert-command))
(defun org-present-hide-cursor ()
"Hide the cursor for current window."
(interactive)
(if cursor-type
(setq-local org-present-cursor-cache cursor-type
cursor-type nil))
(internal-show-cursor (selected-window) nil))
(defun org-present-show-cursor ()
"Show the cursor for current window."
(interactive)
(if org-present-cursor-cache
(setq-local cursor-type org-present-cursor-cache))
(internal-show-cursor (selected-window) t))
;;;###autoload
(defun org-present ()
"Start org presentation."
(interactive)
(setq org-present-mode t)
(org-present-add-overlays)
(run-hooks 'org-present-mode-hook)
(org-present-narrow)
(org-present-run-after-navigate-functions))
(defun org-present-toggle-one-big-page ()
"Toggle showing all pages in a buffer."
(interactive)
(if org-present-one-big-page
(progn
(org-present-narrow)
(setq-local org-present-one-big-page nil))
(widen)
(setq-local org-present-one-big-page t)))
(defun org-present-quit ()
"Quit the minor-mode."
(interactive)
(org-present-small)
(org-present-rm-overlays)
(widen)
;; Exit from read-only mode before exiting the minor mode
(when buffer-read-only
(org-present-read-write))
(run-hooks 'org-present-mode-quit-hook)
(setq org-present-mode nil))
(defvar org-present-startup-folded nil
"Like `org-startup-folded', but for presentation mode.
Also analogous to introduction of slide items by effects in other
presentation programs: i.e., if you do not want to show the whole
slide at first, but to unfurl it slowly, set this to non-nil.")
(defvar org-present-after-navigate-functions nil
"Abnormal hook run after org-present navigates to a new heading.")
;; courtesy Xah Lee ( http://ergoemacs.org/emacs/modernization_elisp_lib_problem.html )
(defun org-present-trim-string (string)
"Remove whitespace (space, tab, emacs newline (LF, ASCII 10)) in beginning and ending of STRING."
(replace-regexp-in-string
"\\`[ \t\n]*" ""
(replace-regexp-in-string "[ \t\n]*\\'" "" string)))
(defun org-present-run-after-navigate-functions ()
"Fold slide if `org-present-startup-folded' is non-nil.
Run org-present-after-navigate hook, passing the name of the presentation buffer and the current heading."
(progn
(if org-present-startup-folded (org-cycle))
(let* ((title-text (thing-at-point 'line))
(safe-title-text (replace-regexp-in-string "^[ \*]" "" title-text))
(current-heading (org-present-trim-string safe-title-text)))
(run-hook-with-args 'org-present-after-navigate-functions (buffer-name) current-heading))))
(provide 'org-present)
;;; org-present.el ends here