Fixing my presentation/demo configuration
This commit is contained in:
parent
c11ab5d0ef
commit
3f84fcd436
3 changed files with 502 additions and 166 deletions
647
ha-demos.org
647
ha-demos.org
|
@ -2,7 +2,8 @@
|
||||||
#+author: Howard X. Abrams
|
#+author: Howard X. Abrams
|
||||||
#+date: 2024-10-18
|
#+date: 2024-10-18
|
||||||
#+filetags: emacs hamacs
|
#+filetags: emacs hamacs
|
||||||
#+lastmod: [2024-11-09 Sat]
|
#+lastmod: [2024-12-16 Mon]
|
||||||
|
#+STARTUP: showstars
|
||||||
|
|
||||||
A literate programming file for creating and running demonstrations
|
A literate programming file for creating and running demonstrations
|
||||||
|
|
||||||
|
@ -57,32 +58,39 @@ But I feel I should replace it, and this project encapsulates the following goal
|
||||||
- Most importantly, a more flexible demonstration where trigger events based on the current /state/.
|
- Most importantly, a more flexible demonstration where trigger events based on the current /state/.
|
||||||
|
|
||||||
* Presentations with Org
|
* Presentations with Org
|
||||||
A demonstration begins with an Org file where the screen shows a /single heading/ with a larger font. Not much more. I have two projects that I like to use.
|
A demonstration begins with an Org file where the screen shows a /single heading/ with a larger font. Not much more. I’m playing around with /all/ the projects available, including writing my own.
|
||||||
** Hiding Blocks
|
** Org Tree Slide
|
||||||
When showing a presentation, I never want the =#+business= to lines to completely disappear. First attempt turned the foreground color to the background color, but that still leaves a blank, but occupied line. Using the invisible overlays removes them completely:
|
I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for years for showing org files as presentations. I like the /simple/ presentation and it seems to shows all the images.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
(defun ha-org-blocks-hide-headers ()
|
(use-package org-tree-slide
|
||||||
"Make the headers and other block metadata invisible.
|
:config
|
||||||
See `ha-org-blocks-show-headers' to return their appearance."
|
(setq org-tree-slide-heading-emphasis nil
|
||||||
(let ((pattern (rx bol (zero-or-more space)
|
org-tree-slide-activate-message "† This demonstration is running in Emacs"
|
||||||
(or ":" "#")
|
org-tree-slide-indicator '(:next nil :previous nil :content nil)
|
||||||
(zero-or-more any) eol)))
|
org-tree-slide-cursor-init nil)
|
||||||
(save-excursion
|
(org-tree-slide-simple-profile)
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward pattern nil t)
|
|
||||||
(let* ((start (match-beginning 0)) (end (1+ (match-end 0)))
|
|
||||||
(ovlay (make-overlay start end)))
|
|
||||||
(overlay-put ovlay 'invisible t))))))
|
|
||||||
|
|
||||||
(defun ha-org-blocks-show-headers ()
|
:bind
|
||||||
"Un-invisibilize the headers and other block metadata invisible.
|
(:map org-tree-slide-mode-map
|
||||||
In other words, this undoes what `ha-org-blocks-hide-headers' did."
|
("<f5>" . org-tree-slide-move-next-tree)
|
||||||
(delete-all-overlays))
|
("S-<f5>" . org-tree-slide-move-previous-tree)
|
||||||
|
("M-<f5>" . org-tree-slide-content)
|
||||||
|
("C-<f5>" . (lambda () (interactive) (org-tree-slide-mode -1))))
|
||||||
|
|
||||||
|
:general
|
||||||
|
(:states 'normal :keymaps 'org-tree-slide-mode-map
|
||||||
|
"C" #'ha-demo-toggle-cursor
|
||||||
|
"n" #'org-tree-slide-move-next-tree
|
||||||
|
"N" #'org-tree-slide-move-previous-tree
|
||||||
|
"Q" (lambda () (interactive) (org-tree-slide-mode -1)))
|
||||||
|
|
||||||
|
:hook
|
||||||
|
((org-tree-slide-play . ha-slide-setup)
|
||||||
|
(org-tree-slide-stop . ha-slide-teardown)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Org Present
|
** Org Present
|
||||||
Converted to use [[https://github.com/rlister/org-present][org-present]]. I love the /hooks/ as that makes it easier to handle. My problem with =org-present= is that it doesn’t always display images.
|
Converted to use [[https://github.com/rlister/org-present][org-present]]. I love the /hooks/ as that makes it easier to handle. My problem with =org-present= is that it doesn’t always display images based on how it handles overlays.
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package org-present
|
(use-package org-present
|
||||||
|
@ -90,37 +98,6 @@ Converted to use [[https://github.com/rlister/org-present][org-present]]. I love
|
||||||
(defvar ha-org-present-mode-line mode-line-format
|
(defvar ha-org-present-mode-line mode-line-format
|
||||||
"Cache previous mode-line format state")
|
"Cache previous mode-line format state")
|
||||||
|
|
||||||
(defun ha-org-present-start ()
|
|
||||||
"Hook to run when starting a presentation.
|
|
||||||
This happens _after_ `org-present' has started."
|
|
||||||
(unless ha-org-present-mode-line
|
|
||||||
(setq ha-org-present-mode-line mode-line-format))
|
|
||||||
(goto-char (point-min)) (re-search-forward (rx bol "*"))
|
|
||||||
(ha-org-blocks-hide-headers)
|
|
||||||
(org-present-big)
|
|
||||||
(org-display-inline-images)
|
|
||||||
(org-present-read-only)
|
|
||||||
(jinx-mode -1) ; Turn off spell checking
|
|
||||||
(evil-normal-state)
|
|
||||||
(setq org-image-actual-width nil)
|
|
||||||
|
|
||||||
;; Clear the demonstration state cache:
|
|
||||||
(clrhash ha-demo-prev-state)
|
|
||||||
|
|
||||||
(setq mode-line-format nil)
|
|
||||||
(org-present-hide-cursor))
|
|
||||||
|
|
||||||
(defun ha-org-present-end ()
|
|
||||||
"Hook to run when ending a presentation.
|
|
||||||
This happens _after_ `org-present-quit' has occurred,
|
|
||||||
and attempts to _undo_ effects of `ha-org-present-start'."
|
|
||||||
(org-present-small)
|
|
||||||
(org-present-read-write)
|
|
||||||
(ha-org-blocks-show-headers)
|
|
||||||
(setq mode-line-format ha-org-present-mode-line)
|
|
||||||
(jinx-mode) ; Turn on spell checking
|
|
||||||
(org-present-show-cursor))
|
|
||||||
|
|
||||||
:bind
|
:bind
|
||||||
(:map org-present-mode-keymap
|
(:map org-present-mode-keymap
|
||||||
("<f5>" . org-present-next)
|
("<f5>" . org-present-next)
|
||||||
|
@ -144,68 +121,322 @@ Converted to use [[https://github.com/rlister/org-present][org-present]]. I love
|
||||||
"Q" #'org-present-quit)
|
"Q" #'org-present-quit)
|
||||||
|
|
||||||
:hook
|
:hook
|
||||||
(org-present-mode . ha-org-present-start)
|
(org-present-mode . ha-slide-setup)
|
||||||
(org-present-mode-quit . ha-org-present-end))
|
(org-present-mode-quit . ha-slide-teardown))
|
||||||
#+end_src
|
#+end_src
|
||||||
** Org Tree Slide
|
** DSlide
|
||||||
I’ve used [[https://github.com/takaxp/org-tree-slide][org-tree-slide]] for years for showing org files as presentations. I like the /simple/ presentation and it seems to shows all the images.
|
The [[https://github.com/positron-solutions/dslide][dslide project]] is flexible, interesting, and can run code.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-tree-slide
|
(use-package dslide
|
||||||
:config
|
:straight (dslide :type git :host github :repo "positron-solutions/dslide")
|
||||||
(setq org-tree-slide-heading-emphasis nil
|
|
||||||
org-tree-slide-activate-message "† This demonstration is running in Emacs"
|
|
||||||
org-tree-slide-indicator '(:next nil :previous nil :content nil)
|
|
||||||
org-tree-slide-cursor-init nil)
|
|
||||||
(org-tree-slide-simple-profile)
|
|
||||||
|
|
||||||
(defun ha-org-tree-slide-start ()
|
:custom
|
||||||
"Configure the presentation display.
|
(dslide-start-from 'point)
|
||||||
See `ha-org-tree-slide-stop' that undoes this."
|
;; Let's keep our presentations simple:
|
||||||
(setq org-hide-emphasis-markers t)
|
(dslide-slide-in-effect nil)
|
||||||
(ha-org-blocks-hide-headers)
|
(dslide-header nil)
|
||||||
(ha-demo-hide-cursor)
|
(dslide-header-date nil)
|
||||||
(ha-demo-hide-mode-line)
|
(dslide-header-author nil)
|
||||||
(ha-demo-presentation-frame)
|
(dslide-header-email nil)
|
||||||
;; (demo-it--presentation-display-set)
|
(dslide-breadcrumb-separator nil)
|
||||||
(text-scale-set 4)
|
|
||||||
(git-gutter-mode -1)
|
|
||||||
(flycheck-mode -1)
|
|
||||||
(jinx-mode -1))
|
|
||||||
|
|
||||||
(defun ha-org-tree-slide-stop ()
|
|
||||||
"Reset the display after a presentation.
|
|
||||||
See `ha-org-tree-slide-start' for what's set."
|
|
||||||
(setq org-hide-emphasis-markers t)
|
|
||||||
(ha-org-blocks-show-headers)
|
|
||||||
(ha-demo-show-cursor)
|
|
||||||
(ha-demo-show-mode-line)
|
|
||||||
(ha-demo-normalize-frame)
|
|
||||||
;; (demo-it--presentation-display-restore) ; Restore previous changes
|
|
||||||
(text-scale-set 0)
|
|
||||||
(git-gutter-mode)
|
|
||||||
(flycheck-mode)
|
|
||||||
(jinx-mode))
|
|
||||||
|
|
||||||
:bind
|
|
||||||
(:map org-tree-slide-mode-map
|
|
||||||
("<f5>" . org-tree-slide-move-next-tree)
|
|
||||||
("S-<f5>" . org-tree-slide-move-previous-tree)
|
|
||||||
("M-<f5>" . org-tree-slide-content)
|
|
||||||
("C-<f5>" . (lambda () (interactive) (org-tree-slide-mode -1))))
|
|
||||||
|
|
||||||
:general
|
:general
|
||||||
(:states 'normal :keymaps 'org-tree-slide-mode-map
|
(:states 'normal :no-autoload t :keymaps 'dslide-mode-map
|
||||||
"C" #'ha-demo-toggle-cursor
|
"q" '("quit presentation" . dslide-deck-stop)
|
||||||
"n" #'org-tree-slide-move-next-tree
|
"<left>" '("previous slide" . dslide-deck-backward)
|
||||||
"N" #'org-tree-slide-move-previous-tree
|
"<right>" '("next slide" . dslide-deck-forward)
|
||||||
"Q" (lambda () (interactive) (org-tree-slide-mode -1)))
|
"C" '("show cursor" . ha-demo-show-cursor)
|
||||||
|
"c" '("hide cursor" . ha-demo-hide-cursor)
|
||||||
|
"<up>" '("previous slide" . previous-line)
|
||||||
|
"<down>" '("next slide" . next-line))
|
||||||
|
|
||||||
:hook
|
:bind
|
||||||
((org-tree-slide-play . ha-org-tree-slide-start)
|
("C-<f5>" . dslide-deck-start)
|
||||||
(org-tree-slide-stop . ha-org-tree-slide-stop)))
|
(:map dslide-mode-map
|
||||||
|
("<f5>" . dslide-deck-forward)
|
||||||
|
("S-<f5>" . dslide-deck-backward)
|
||||||
|
("C-<f5>" . dslide-deck-stop))
|
||||||
|
|
||||||
|
:hook ((dslide-start . ha-slide-setup)
|
||||||
|
(dslide-stop . ha-slide-teardown)
|
||||||
|
(dslide-narrow . ha-slide-reset)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Let’s try it out by loading this example.[[file:~/.emacs.d/straight/repos/dslide/test/demo.org][ demo.org]]
|
||||||
|
|
||||||
|
What features do I like and want to take advantage of?
|
||||||
|
- Inline Children show: =:DSLIDE_SLIDE_ACTION: dslide-slide-action-inline=
|
||||||
|
- Flat Slide (shows children section immediately): =:DSLIDE_SLIDE_ACTION: dslide-slide-action-flat=
|
||||||
|
- Show images only? I guess we could use my own thing, but it is nice and easy: =:DSLIDE_ACTIONS: dslide-action-image :slide-display nil=
|
||||||
|
- No header slides: =:DSLIDE_SLIDE_ACTION: dslide-slide-action-child :header nil=
|
||||||
|
- Re-execute Babel blocks: =:DSLIDE_SLIDE_ACTION: dslide-slide-babel=
|
||||||
|
- Hiding Blocks
|
||||||
|
- Results Only
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
|
(use-package dslide
|
||||||
|
:config
|
||||||
|
;; The dslide-highlight inherits from 'highlight'
|
||||||
|
;; (set-face-attribute dslide-highlight :foreground "red")
|
||||||
|
;; This too inherits from 'highlight'
|
||||||
|
;; (set-face-attribute dslide-babel-success-highlight :foreground "red")
|
||||||
|
;; This inherits from `error'
|
||||||
|
;; (set-face-attribute dslide-babel-error-highlight :foreground "red")
|
||||||
|
(set-face-attribute 'highlight nil :background 'unspecified :foreground "lightblue"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Master of Ceremonies
|
||||||
|
The [[https://github.com/positron-solutions/moc][Master of Ceremonies]] package (moc) is to help when recording Emacs screens. Early in development, but it looks to have some potential. Not sure how to use it yet.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
|
(use-package default-text-scale)
|
||||||
|
|
||||||
|
(use-package moc
|
||||||
|
:straight (:type git :host github
|
||||||
|
:repo "positron-solutions/moc"))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Select text, and call =moc-focus= (call =moc-focus-quit= to stop). Highlight more text, and call =moc-focus-highlight= to brighten it, or =moc-focus-obscure= to hide it.
|
||||||
|
|
||||||
|
The =moc-screenshot= seems to only work on Linux.
|
||||||
|
|
||||||
|
An interesting approach for making presentations, that I’m not sure I will need.
|
||||||
|
|
||||||
|
*** Showing Something associated with a Headline
|
||||||
|
:PROPERTIES:
|
||||||
|
:DSLIDE_ACTIONS: dslide-action-babel
|
||||||
|
:END:
|
||||||
|
|
||||||
|
When I give a /demonstration/ (uising my [[New Demonstration]] project), I could, instead, use a custom =dslide= action.
|
||||||
|
|
||||||
|
But how would I get it to close? Maybe we use a combination of actions and my “demo” code for everything else?
|
||||||
|
|
||||||
|
*Note:* Code blocks with =exports= set to =none= are not displayed.
|
||||||
|
|
||||||
|
#+begin_src elisp :tangle no :exports none :results none
|
||||||
|
(ha-demo-show-file "ha-org.org" :position 'right
|
||||||
|
:focus 'presentation :heading "Meetings"
|
||||||
|
:shift 0)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp :tangle no :exports none :results none
|
||||||
|
(ha-demo-highlight-buffer :buffer "ha-org.org"
|
||||||
|
:hi-lines "268-274")
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+begin_src elisp :tangle no :exports none :results none
|
||||||
|
(delete-other-windows)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Bullet/Paragraph Highlighting
|
||||||
|
I would like to highlight a bullet point or a paragraph while talking.
|
||||||
|
To do this, add =:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs= to the properties of a section.
|
||||||
|
|
||||||
|
#+begin_src elisp emacs-lisp
|
||||||
|
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
||||||
|
((overlays :initform nil))
|
||||||
|
"Paint the paragraphs with the highlight color, one by one.")
|
||||||
|
|
||||||
|
;; Default no-op `dslide-begin' is sufficient
|
||||||
|
|
||||||
|
;; Default implementation of `dslide-end', which just plays forward to the end,
|
||||||
|
;; is well-behaved with this class.
|
||||||
|
|
||||||
|
;; Remove any remaining overlays when calling final.
|
||||||
|
(cl-defmethod dslide-final :after ((obj dslide-action-highlight-paragraphs))
|
||||||
|
(mapc #'delete-overlay (oref obj overlays)))
|
||||||
|
|
||||||
|
;; Find the next paragraph and add an overlay if it exists
|
||||||
|
(cl-defmethod dslide-forward ((obj dslide-action-highlight-paragraphs))
|
||||||
|
;; This line removes all overlays allowing us to highlight a new one.
|
||||||
|
;; Remove this if you want the paragraphs to _linger_.
|
||||||
|
(mapc #'delete-overlay (oref obj overlays))
|
||||||
|
(when-let ((paragraph (dslide-section-next obj 'paragraph)))
|
||||||
|
(let* ((beg (org-element-property :begin paragraph))
|
||||||
|
(end (org-element-property :end paragraph))
|
||||||
|
(new-overlay (make-overlay beg end)))
|
||||||
|
(overlay-put new-overlay 'face 'highlight)
|
||||||
|
(push new-overlay (oref obj overlays))
|
||||||
|
;; Return non-nil to indicate progress was made. This also informs the
|
||||||
|
;; highlight when following the slides in the base buffer.
|
||||||
|
beg)))
|
||||||
|
|
||||||
|
(cl-defmethod dslide-backward ((obj dslide-action-highlight-paragraphs))
|
||||||
|
(when-let* ((overlay (pop (oref obj overlays))))
|
||||||
|
(delete-overlay overlay)
|
||||||
|
;; If there is a preceding overlay, move to its beginning else move to the
|
||||||
|
;; beginning of the heading.
|
||||||
|
(if-let ((overlay (car (oref obj overlays))))
|
||||||
|
(dslide-marker obj (overlay-start overlay))
|
||||||
|
(dslide-marker obj (org-element-property :begin (dslide-heading obj))))))
|
||||||
|
#+end_src
|
||||||
|
*** Custom Action Demo
|
||||||
|
:PROPERTIES:
|
||||||
|
:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs
|
||||||
|
:END:
|
||||||
|
Massachusetts, in particular, has always been one of the laboratories of democracy. It's where people try things before they're popular. It's where we experiment.
|
||||||
|
|
||||||
|
- Red
|
||||||
|
- Orange
|
||||||
|
- Yellow
|
||||||
|
|
||||||
|
Democracy depends on an informed citizenry and the social cohesion that those citizens can show even when they disagree.
|
||||||
|
|
||||||
|
The essence of democracy is the resolve of individuals working together to shape our institutions and our society in ways that allow all of us to flourish.
|
||||||
|
** My Slides
|
||||||
|
A /full/ presentation requires my /notes/ on one frame, and the presentation on the other.
|
||||||
|
|
||||||
|
To use this, following:
|
||||||
|
1. Select the Org mode presentation
|
||||||
|
2. Run the function, =ha-slide-make-notes-frame=
|
||||||
|
3. Reference the notes file that would be associated with the presentation
|
||||||
|
|
||||||
|
The end result is two frames, where updating the presentation, updates the location of the other frame to match the same headline.
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defvar ha-slide-notes-frame-name "Demonstration Notes"
|
||||||
|
"The name of the frame that displays the presentation notes.")
|
||||||
|
|
||||||
|
(defvar ha-slide-notes-frame nil
|
||||||
|
"Frame containing the presentation notes.")
|
||||||
|
|
||||||
|
(defvar ha-slide-notes-window nil
|
||||||
|
"Window containing the presentation notes.")
|
||||||
|
|
||||||
|
(defun ha-slide-make-notes-frame (filename &optional heading)
|
||||||
|
"Display the notes, FILENAME, in a new frame.
|
||||||
|
If HEADING is given, jump to that `org-mode' headline."
|
||||||
|
(interactive "fNotes File: ")
|
||||||
|
(let ((f (selected-frame)))
|
||||||
|
(setq ha-slide-notes-frame
|
||||||
|
(make-frame `((name . ,ha-slide-notes-frame-name))))
|
||||||
|
(set-frame-position ha-slide-notes-frame 1310 0)
|
||||||
|
(set-frame-size ha-slide-notes-frame 920 1420 t)
|
||||||
|
|
||||||
|
;; While I could call `find-file-other-frame', I want to make
|
||||||
|
;; sure I get the file loaded in the correct frame:
|
||||||
|
(x-focus-frame ha-slide-notes-frame)
|
||||||
|
(find-file filename)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(when heading
|
||||||
|
(re-search-forward (rx bol (one-or-more "*") (one-or-more space) (literal heading)))
|
||||||
|
(recenter-top-bottom 0))
|
||||||
|
|
||||||
|
(setq ha-slide-notes-window (selected-window))
|
||||||
|
(delete-other-windows)
|
||||||
|
|
||||||
|
;; Highlight the original window containing the presentation:
|
||||||
|
(x-focus-frame f)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
These interactive functions scroll the “notes” in the other window in another frame:
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(defun ha-slide-notes-scroll-up ()
|
||||||
|
"Scroll the frame/window containing the notes, up."
|
||||||
|
(interactive)
|
||||||
|
(when ha-slide-notes-window
|
||||||
|
(with-selected-window ha-slide-notes-window
|
||||||
|
(scroll-up -10))))
|
||||||
|
|
||||||
|
(defun ha-slide-notes-scroll-down ()
|
||||||
|
"Scroll the frame/window containing the notes, down."
|
||||||
|
(interactive)
|
||||||
|
(when ha-slide-notes-window
|
||||||
|
(with-selected-window ha-slide-notes-window
|
||||||
|
(scroll-up 10))))
|
||||||
|
|
||||||
|
(defun ha-slide-notes-update ()
|
||||||
|
"Function to move the notes headline to current buffers.
|
||||||
|
Assuming the buffer is showing an org-file, and previously
|
||||||
|
called `ha-slide-make-notes-frame', this function moves
|
||||||
|
the point in that buffer to the same headline."
|
||||||
|
(interactive)
|
||||||
|
(when ha-slide-notes-window
|
||||||
|
(let ((heading (thread-first
|
||||||
|
(org-get-heading t t t t)
|
||||||
|
(substring-no-properties))))
|
||||||
|
(with-selected-window ha-slide-notes-window
|
||||||
|
(goto-char (point-min))
|
||||||
|
(re-search-forward (rx (literal heading)) nil t)
|
||||||
|
(recenter-top-bottom 0)))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Call the =ha-slide-notes-update= function automatically after updating a slide. With =dslide=, we add a hook:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(use-package dslide
|
||||||
|
:hook (dslide-narrow . 'ha-slide-notes-update))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
** My Presentation View
|
||||||
|
Regardless of the presentation package I use, I make them all look similar with the following code. Much of this is getting rid of Emacs visual elements, like the cursor and the mode-line, as well as stopping minor modes that add visual changes, like spellchecking and the gutter. I can call this function from any presentation software used.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-slide-setup (&optional frame-name)
|
||||||
|
"Configure the look I want for presentations.
|
||||||
|
The frame associated with FRAME-NAME is tidied
|
||||||
|
by removing the gutters and other informative
|
||||||
|
widgets not needed for a presentation."
|
||||||
|
(org-indent-mode -1)
|
||||||
|
;; (org-modern-mode -1)
|
||||||
|
|
||||||
|
(setq org-image-actual-width nil)
|
||||||
|
(org-display-inline-images)
|
||||||
|
(ha-org-blocks-hide-headers)
|
||||||
|
(ha-org-hide-stars)
|
||||||
|
(font-lock-update)
|
||||||
|
(ha-demo-hide-mode-line)
|
||||||
|
(ha-demo-hide-cursor)
|
||||||
|
(ha-demo-presentation-frame frame-name)
|
||||||
|
|
||||||
|
(text-scale-set 4)
|
||||||
|
(git-gutter-mode -1)
|
||||||
|
(flycheck-mode -1)
|
||||||
|
(jinx-mode -1)
|
||||||
|
|
||||||
|
;; Clear the demonstration state cache:
|
||||||
|
(clrhash ha-demo-prev-state)
|
||||||
|
|
||||||
|
(evil-normal-state))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
And after a presentation finishes, this function cleans up by restoring minor modes, etc:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-slide-teardown ()
|
||||||
|
"Reset the Org after a presentation."
|
||||||
|
(org-indent-mode 1)
|
||||||
|
;; (org-modern-mode 1)
|
||||||
|
|
||||||
|
(ha-org-blocks-show-headers)
|
||||||
|
(font-lock-update)
|
||||||
|
(ha-demo-show-mode-line)
|
||||||
|
(ha-demo-show-cursor)
|
||||||
|
(ha-demo-normalize-frame)
|
||||||
|
|
||||||
|
(text-scale-set 0)
|
||||||
|
(git-gutter-mode)
|
||||||
|
(flycheck-mode)
|
||||||
|
(jinx-mode))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
The =dslide= seems to reset /everything/ on each slide display, so:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-slide-reset ()
|
||||||
|
"Reset the current slide."
|
||||||
|
(interactive)
|
||||||
|
(ha-org-blocks-hide-headers)
|
||||||
|
(font-lock-update))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
* New Demonstration
|
* New Demonstration
|
||||||
Instead of executing a sequence of demonstration steps, demonstrations key on “state”, that is, the active buffer or major-mode, or the heading of an Org file, etc. I described the [[https://howardism.org/Technical/Emacs/demonstrations-part-two.html][guts of writing this code]], but we bind a key to calling =ha-demo-step= with a list of /state matchers/ to functions to call when matched. For instance:
|
Instead of executing a sequence of demonstration steps, demonstrations key on “state”, that is, the active buffer or major-mode, or the heading of an Org file, etc. I described the [[https://howardism.org/Technical/Emacs/demonstrations-part-two.html][guts of writing this code]], but we bind a key to calling =ha-demo-step= with a list of /state matchers/ to functions to call when matched. For instance:
|
||||||
|
|
||||||
|
@ -264,7 +495,7 @@ The matching function, =ha-demo-state-match= looks in a cache, the =demo-prev-st
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun ha-demo-state-match (triggers state)
|
(defun ha-demo-state-match (triggers state)
|
||||||
"Return non-nil if STATE contains all TRIGGERS.
|
"Return non-nil if STATE has all TRIGGERS.
|
||||||
The state also includes the number of times the triggers
|
The state also includes the number of times the triggers
|
||||||
matched during previous calls. We do this by keeping track
|
matched during previous calls. We do this by keeping track
|
||||||
of the number of successful calls, and incrementing
|
of the number of successful calls, and incrementing
|
||||||
|
@ -338,13 +569,51 @@ Let’s create a function that could accept a list of /triggering keys/, and the
|
||||||
* Demonstration Support
|
* Demonstration Support
|
||||||
What sort of functions will I often be doing?
|
What sort of functions will I often be doing?
|
||||||
|
|
||||||
|
** Hiding Blocks
|
||||||
|
When showing a presentation, I never want the =#+business= to lines to completely disappear. First attempt turned the foreground color to the background color, but that still leaves a blank, but occupied line. Using the invisible overlays removes them completely:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-org-blocks-hide-headers ()
|
||||||
|
"Make the headers and other block metadata invisible.
|
||||||
|
See `ha-org-blocks-show-headers' to return their appearance."
|
||||||
|
(let ((pattern (rx bol (zero-or-more space)
|
||||||
|
(or ":" "#")
|
||||||
|
(zero-or-more any) eol)))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward pattern nil t)
|
||||||
|
(let* ((start (match-beginning 0)) (end (1+ (match-end 0)))
|
||||||
|
(ovlay (make-overlay start end)))
|
||||||
|
(overlay-put ovlay 'invisible t))))))
|
||||||
|
|
||||||
|
(defun ha-org-blocks-show-headers ()
|
||||||
|
"Un-invisibilize the headers and other block metadata invisible.
|
||||||
|
In other words, this undoes what `ha-org-blocks-hide-headers' did."
|
||||||
|
(delete-all-overlays))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
What about deleting the initial bullets in =org-indent-mode=:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-org-hide-stars ()
|
||||||
|
"Create overlay to hide all initial astericks in Org headlines."
|
||||||
|
(let ((pattern (rx bol (one-or-more "*") (one-or-more space))))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (re-search-forward pattern nil t)
|
||||||
|
(let* ((start (match-beginning 0))
|
||||||
|
(end (1+ (match-end 0)))
|
||||||
|
(ovlay (make-overlay start end)))
|
||||||
|
(overlay-put ovlay 'invisible t))))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
** Hide and Show the Cursor
|
** Hide and Show the Cursor
|
||||||
The typical presentation software has an issue for hiding the cursor when working with Evil mode, and since setting =cursor-type= to =nil= doesn’t work in a graphical display (where we typically run a presentation), the following functions turn on/off the displayed cursor.
|
The typical presentation software has an issue for hiding the cursor when working with Evil mode, and since setting =cursor-type= to =nil= doesn’t work in a graphical display (where we typically run a presentation), the following functions turn on/off the displayed cursor.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar ha-demo-cursor nil
|
(defvar ha-demo-cursor nil
|
||||||
"List of cursor states stored during `ha-demo-hide-cursor' and
|
"List of cursor states stored during `ha-demo-hide-cursor'.
|
||||||
restored with `ha-demo-show-cursor'.")
|
Used to restore with `ha-demo-show-cursor'.")
|
||||||
|
|
||||||
(defun ha-demo-hide-cursor ()
|
(defun ha-demo-hide-cursor ()
|
||||||
"Hide the cursor for the current frame."
|
"Hide the cursor for the current frame."
|
||||||
|
@ -392,7 +661,7 @@ The typical presentation software has an issue for hiding the cursor when workin
|
||||||
(setq ha-demo-cursor nil)))
|
(setq ha-demo-cursor nil)))
|
||||||
|
|
||||||
(defun ha-demo-toggle-cursor ()
|
(defun ha-demo-toggle-cursor ()
|
||||||
"Toggles the display of the cursor."
|
"Toggle cursor display from shown or hidden."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if ha-demo-cursor
|
(if ha-demo-cursor
|
||||||
(ha-demo-show-cursor)
|
(ha-demo-show-cursor)
|
||||||
|
@ -418,15 +687,16 @@ For Org file displayed as presentations as well as images, we probably don’t w
|
||||||
(interactive)
|
(interactive)
|
||||||
(if ha-demo-mode-line
|
(if ha-demo-mode-line
|
||||||
(setq mode-line-format ha-demo-mode-line)))
|
(setq mode-line-format ha-demo-mode-line)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Presentation Frame Properties
|
** Presentation Frame Properties
|
||||||
Like the work I’m doing to the mode-line, can we make the frame cleaner for a presentation?
|
Like the work I’m doing to the mode-line, can we make the frame cleaner for a presentation?
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar ha-demo-frame-state nil
|
(defvar ha-demo-frame-state nil
|
||||||
"Store frame properties during `ha-demo-presentation-frame' before
|
"Store frame properties during `ha-demo-presentation-frame'.
|
||||||
altering them, and then restore them with `ha-demo-normalize-frame'.")
|
Stored before alteration, as to restore them with
|
||||||
|
`ha-demo-normalize-frame'.")
|
||||||
|
|
||||||
(defun ha-demo-presentation-frame (&optional name)
|
(defun ha-demo-presentation-frame (&optional name)
|
||||||
"Remove the fringe and other frame settings.
|
"Remove the fringe and other frame settings.
|
||||||
|
@ -446,7 +716,7 @@ Like the work I’m doing to the mode-line, can we make the frame cleaner for a
|
||||||
(interactive)
|
(interactive)
|
||||||
(set-frame-parameter (selected-frame) 'left-fringe (nth 0 ha-demo-frame-state))
|
(set-frame-parameter (selected-frame) 'left-fringe (nth 0 ha-demo-frame-state))
|
||||||
(set-frame-parameter (selected-frame) 'right-fringe (nth 1 ha-demo-frame-state)))
|
(set-frame-parameter (selected-frame) 'right-fringe (nth 1 ha-demo-frame-state)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Display File
|
** Display File
|
||||||
Displaying a File with:
|
Displaying a File with:
|
||||||
|
@ -461,7 +731,7 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters?
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(cl-defun ha-demo-show-file (filename &key position size modeline
|
(cl-defun ha-demo-show-file (filename &key position size modeline
|
||||||
line heading shift cursor
|
line heading shift cursor
|
||||||
commands)
|
commands focus)
|
||||||
"Show a file, FILENAME, in a buffer based on keyed parameters.
|
"Show a file, FILENAME, in a buffer based on keyed parameters.
|
||||||
POSITION can be 'full 'right or 'below and positions the window.
|
POSITION can be 'full 'right or 'below and positions the window.
|
||||||
SIZE is an integer for the font size based on the default size.
|
SIZE is an integer for the font size based on the default size.
|
||||||
|
@ -470,59 +740,49 @@ All options? Should I use Common Lisp’s =cl-defun= for the keyword parameters?
|
||||||
HEADING is a headline from the currently display Org file.
|
HEADING is a headline from the currently display Org file.
|
||||||
SHIFT is the number of lines above the point to show, in case
|
SHIFT is the number of lines above the point to show, in case
|
||||||
the LINE shouldn't be at the top of the window.
|
the LINE shouldn't be at the top of the window.
|
||||||
|
The CURSOR can be 'show / 'yes or 'hide / 'no.
|
||||||
|
The FOCUS can be 'presentation to return the cursor to the
|
||||||
|
calling buffer.
|
||||||
|
|
||||||
COMMANDS is a lambda expression that can contain any other
|
COMMANDS is a lambda expression that can contain any other
|
||||||
instructions to happen to the buffer display."
|
instructions to happen to the buffer display."
|
||||||
(unless position
|
(let ((orig-buf (current-buffer)))
|
||||||
(setq position :right))
|
(unless position
|
||||||
|
(setq position :right))
|
||||||
|
|
||||||
;; Step 1: Create a window
|
;; Step 1: Create a window
|
||||||
(pcase position
|
(pcase position
|
||||||
('above (progn (split-window-vertically)))
|
('above (progn (split-window-vertically)))
|
||||||
('up (progn (split-window-vertically)))
|
('up (progn (split-window-vertically)))
|
||||||
('left (progn (split-window-horizontally)))
|
('left (progn (split-window-horizontally)))
|
||||||
('right (progn (split-window-horizontally) (other-window 1)))
|
('right (progn (split-window-horizontally) (other-window 1)))
|
||||||
('above (progn (split-window-vertically) (other-window 1)))
|
('above (progn (split-window-vertically) (other-window 1)))
|
||||||
('below (progn (split-window-vertically) (other-window 1))))
|
('below (progn (split-window-vertically) (other-window 1))))
|
||||||
|
|
||||||
;; Step 2: Load the file or switch to the buffer:
|
;; Step 2: Load the file or switch to the buffer:
|
||||||
(if (file-exists-p filename)
|
(if (file-exists-p filename)
|
||||||
(find-file filename)
|
(find-file filename)
|
||||||
(switch-to-buffer filename))
|
(switch-to-buffer filename))
|
||||||
|
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
|
|
||||||
(when cursor
|
(when cursor
|
||||||
(if (or (eq cursor 'yes) (eq cursor 'show))
|
(if (or (eq cursor 'yes) (eq cursor 'show))
|
||||||
(ha-demo-show-cursor)
|
(ha-demo-show-cursor)
|
||||||
(ha-demo-hide-cursor)))
|
(ha-demo-hide-cursor)))
|
||||||
|
|
||||||
;; Step 3: Increase the font size
|
;; Step 3: Increase the font size
|
||||||
(when size
|
(when size
|
||||||
(text-scale-set size))
|
(text-scale-set size))
|
||||||
|
|
||||||
(when line
|
(unless modeline
|
||||||
(if (integerp line)
|
(setq-local mode-line-format nil))
|
||||||
(forward-line line)
|
|
||||||
(re-search-forward line nil t)))
|
|
||||||
|
|
||||||
(when heading
|
(ha-demo-highlight-buffer :line line :heading heading :shift shift
|
||||||
(re-search-forward (rx bol (one-or-more "*") (one-or-more space)
|
:commands commands)
|
||||||
(literal heading))
|
|
||||||
nil t))
|
|
||||||
|
|
||||||
;; If SHIFT is positive integer, left that many line above point,
|
(when (and focus (eq focus 'presentation))
|
||||||
;; otherwise don't do anything to leave it in the middle.
|
(pop-to-buffer orig-buf))))
|
||||||
;; If SHIFT is null, move it to the top of the buffer window:
|
|
||||||
(if shift
|
|
||||||
(when (integerp shift)
|
|
||||||
(recenter-top-bottom shift))
|
|
||||||
(recenter-top-bottom 0))
|
|
||||||
|
|
||||||
(unless modeline
|
|
||||||
(setq-local mode-line-format nil))
|
|
||||||
|
|
||||||
(when commands (funcall commands)))
|
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Let try it all together:
|
Let try it all together:
|
||||||
|
@ -539,6 +799,75 @@ Or:
|
||||||
:commands (lambda () (jinx-mode -1)))
|
:commands (lambda () (jinx-mode -1)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
** Highlight Text in Buffer
|
||||||
|
Perhaps when we call =ha-demo-show-file=, we want to highlight different parts of the file?
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defface ha-demo-highlight-1 '((t :weight ultra-heavy))
|
||||||
|
"Face used for highlighting alternate buffers.")
|
||||||
|
|
||||||
|
(defface ha-demo-highlight-2 '((t :slant italic))
|
||||||
|
"Face used for highlighting alternate buffers.")
|
||||||
|
|
||||||
|
(defface ha-demo-highlight-3 '((t :background "#0000a0" :extend t))
|
||||||
|
"Face used for highlighting alternate buffers.")
|
||||||
|
|
||||||
|
(cl-defun ha-demo-highlight-buffer (&key buffer line heading shift
|
||||||
|
hi-lines hi-face commands)
|
||||||
|
"Move to a section of a buffer, and possibly highlight text.
|
||||||
|
If BUFFER is given, call `pop-to-buffer' on that.
|
||||||
|
If LINE, HEADING, or SHIFT is given, move to that section.
|
||||||
|
If HI-LINES is given, create an overlay for those lines
|
||||||
|
based on the face, HI-FACE (if that isn't given, bold those lines).
|
||||||
|
Finally execute COMMANDS, if given."
|
||||||
|
(when buffer
|
||||||
|
(pop-to-buffer buffer))
|
||||||
|
|
||||||
|
(when line
|
||||||
|
(if (integerp line)
|
||||||
|
(forward-line line)
|
||||||
|
(re-search-forward line nil t)))
|
||||||
|
|
||||||
|
(when heading
|
||||||
|
(re-search-forward (rx bol (one-or-more "*") (one-or-more space)
|
||||||
|
(literal heading))
|
||||||
|
nil t))
|
||||||
|
|
||||||
|
;; If SHIFT is positive integer, left that many line above point,
|
||||||
|
;; otherwise don't do anything to leave it in the middle.
|
||||||
|
;; If SHIFT is null, move it to the top of the buffer window:
|
||||||
|
(when shift
|
||||||
|
(if (integerp shift)
|
||||||
|
(recenter-top-bottom shift))
|
||||||
|
(recenter-top-bottom 0))
|
||||||
|
|
||||||
|
(when hi-lines
|
||||||
|
(remove-overlays)
|
||||||
|
(seq-let (first-line last-line) (string-split hi-lines (rx (or ":" "-")))
|
||||||
|
(save-excursion
|
||||||
|
(let* ((beg (goto-line (string-to-number first-line)))
|
||||||
|
(end (progn
|
||||||
|
(goto-line (string-to-number last-line))
|
||||||
|
(line-end-position)))
|
||||||
|
(new-overlay (make-overlay beg end)))
|
||||||
|
|
||||||
|
(if hi-face
|
||||||
|
(overlay-put new-overlay 'face hi-face)
|
||||||
|
(overlay-put new-overlay 'face ha-demo-highlight-2))
|
||||||
|
|
||||||
|
;; (push new-overlay (oref obj overlays))
|
||||||
|
))))
|
||||||
|
|
||||||
|
(when commands (funcall commands)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
|
(ha-demo-highlight-buffer :hi-lines "874-881" :hi-face 'ha-demo-highlight-3)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
* Technical Artifacts :noexport:
|
* Technical Artifacts :noexport:
|
||||||
Let's =provide= a name so we can =require= this file:
|
Let's =provide= a name so we can =require= this file:
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,7 @@ Which font to choose?
|
||||||
:straight (:host github :repo "jabranham/mixed-pitch")
|
:straight (:host github :repo "jabranham/mixed-pitch")
|
||||||
:config
|
:config
|
||||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-property-value)
|
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-property-value)
|
||||||
|
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-special-keyword)
|
||||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'font-lock-comment-face)
|
(add-to-list 'mixed-pitch-fixed-pitch-faces 'font-lock-comment-face)
|
||||||
:hook (text-mode . mixed-pitch-mode))
|
:hook (text-mode . mixed-pitch-mode))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
|
@ -82,23 +82,29 @@ The following adds frame borders and window dividers to give space between windo
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Hide Heading Stars
|
** Hide Heading Stars
|
||||||
I’ve struggled with hiding the initial asterisks that denote a headline in Org.
|
I’ve struggled with hiding the initial asterisks that denote a headline in Org. The following code doesn’t work with how the built-in [[https://orgmode.org/manual/Org-Indent-Mode.html][org-indent-mode]] works.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp :tangle no
|
||||||
(defun org-mode-hide-stars ()
|
(defun org-mode-hide-stars ()
|
||||||
(font-lock-add-keywords
|
(font-lock-add-keywords
|
||||||
nil
|
nil
|
||||||
'(("^\\*+ "
|
`(( ,(rx line-start (one-or-more "*") space)
|
||||||
(0 (put-text-property (match-beginning 0) (match-end 0) 'face
|
(0 (put-text-property (match-beginning 0) (match-end 0)
|
||||||
(list :foreground
|
'invisible t))))))
|
||||||
(face-attribute 'default :background))))))))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
And hook this function to Org:
|
And hook this function to Org:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package org
|
(use-package org
|
||||||
:hook (org-mode . org-mode-hide-stars))
|
:hook (org-mode . org-mode-hide-stars))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
The list of things to try:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq org-hide-leading-stars nil) ; or t
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
** Markup View
|
** Markup View
|
||||||
The variable, =org-hide-emphasis-markers=, is key to pretending that Emacs can be a word processor, however, since the org markup controls aren’t viewable, I find it challenging at times, to change that. The [[https://github.com/awth13/org-appear][org-appear project]] seeks to fix this by showing the markup when the point is nearby:
|
The variable, =org-hide-emphasis-markers=, is key to pretending that Emacs can be a word processor, however, since the org markup controls aren’t viewable, I find it challenging at times, to change that. The [[https://github.com/awth13/org-appear][org-appear project]] seeks to fix this by showing the markup when the point is nearby:
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue