Protesilaos has a simple fix for [[https://protesilaos.com/codelog/2024-11-28-basic-emacs-configuration/#h:1e468b2a-9bee-4571-8454-e3f5462d9321][closing minibuffer with C-g]]. His explanation:
#+begin_quote
Do-What-I-Mean behaviour for a general keyboard-quit. The generic keyboard-quit does not do the expected thing when the minibuffer is open. Whereas we want it to close the minibuffer, even without explicitly focusing it. The DWIM behaviour of this command is as follows:
- When the region is active, disable it.
- When a minibuffer is open, but not focused, close the minibuffer.
- When the Completions buffer is selected, close it.
- In every other case use the regular keyboard-quit.
After reading [[https://irreal.org/blog/?p=12139][Jon Sander’s essay]] as well as [[https://mbork.pl/2024-04-27_Emacs_everywhere][Marcin Borkowski's essay]], I decided to try out Tecosaur’s [[https://github.com/tecosaur/emacs-everywhere][Emacs Everywhere]] approach:
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/.
* 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.
**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:
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.
**Org Tree Slide
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
(defun ha-org-blocks-hide-headers ()
"Make the headers and other block metadata invisible.
See `ha-org-blocks-show-headers' to return their appearance."
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
(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
"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
(:map org-present-mode-keymap
("<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)
:hook
(org-present-mode . ha-org-present-start)
(org-present-mode-quit . ha-org-present-end))
(org-present-mode . ha-slide-setup)
(org-present-mode-quit . ha-slide-teardown))
#+end_src
**Org Tree Slide
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.
**DSlide
The [[https://github.com/positron-solutions/dslide][dslide project]] is flexible, interesting, and can run code.
#+BEGIN_SRC emacs-lisp
(use-package org-tree-slide
:config
(setq org-tree-slide-heading-emphasis nil
org-tree-slide-activate-message "† This demonstration is running in Emacs"
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.
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.
;; 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
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
(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
matched during previous calls. We do this by keeping track
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
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."
"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
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
(defvar ha-demo-cursor nil
"List of cursor states stored during `ha-demo-hide-cursor' and
restored with `ha-demo-show-cursor'.")
"List of cursor states stored during `ha-demo-hide-cursor'.
Used to restore with `ha-demo-show-cursor'.")
(defun ha-demo-hide-cursor ()
"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)))
(defun ha-demo-toggle-cursor ()
"Toggles the display of the cursor."
"Toggle cursor display from shown or hidden."
(interactive)
(if ha-demo-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)
(if ha-demo-mode-line
(setq mode-line-format ha-demo-mode-line)))
#+END_SRC
#+END_SRC
** Presentation Frame Properties
Like the work I’m doing to the mode-line, can we make the frame cleaner for a presentation?
#+BEGIN_SRC emacs-lisp
(defvar ha-demo-frame-state nil
"Store frame properties during `ha-demo-presentation-frame' before
altering them, and then restore them with `ha-demo-normalize-frame'.")
"Store frame properties during `ha-demo-presentation-frame'.
@ -82,23 +82,29 @@ The following adds frame borders and window dividers to give space between windo
#+end_src
** 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.
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: