A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/positron-solutions/dslide.git below:

positron-solutions/dslide: Present anything Emacs can do with programmable, extensible, configurable slides & presentation steps made from org mode headings

0001-2865.mp4

Programmable Org Presentation ๐Ÿฆ„

Everything in ./test/demo.org is maintained. File issues.

Emojis indicate work-in-progress ๐Ÿšง, intended deprecation โ›”, or experimental features ๐Ÿงช.

Subscribe to Positron's YouTube for updates and related demonstrations.

;; From MELPA or ELPA
(use-package dslide)

;; package-vc
(package-vc-install
 '(dslide
   :url "https://github.com/positron-solutions/dslide.git"))

;; using elpaca's with explicit recipe
(use-package dslide
    :ensure (dslide :host github
                    :repo "positron-solutions/dslide"))

;; straight with explicit recipe
(use-package dslide
    :straight (dslide :type git :host github
                      :repo "positron-solutions/dslide"))

;; or use manual load-path & require, you brave yak shaver

Clone the repo and then open the ./test/demo.org file. Call dslide-deck-start. The presentation will explain everything else while demonstrating Dslide.

You will need VLC installed and the Master of Ceremonies package to successfully run all examples, but you can skip them in the contents view or start at point on other examples to go around them.

Fully programmable sequences behind a two-button presentation interface:

The default dslide-mode-map uses arrow keys. Left and right are dslide-deck-forward and dslide-deck-backward. Up is dslide-deck-start and will show the contents. Down is dslide-deck-stop and will stop the slide show.

Call dslide-contents to show a contents overview. Calling dslide-deck-forward and dslide-deck-backward in the contents can quickly move through headings. Call dslide-deck-start again to resume the presentation from that point.

Check out dslide-deck-develop. You can see your hidden comments and the approximate progress indications. Babel actions will highlight blocks as they execute, showing you what just happened.

By default, the dslide-action-hide-markup action is configured in dslide-default-actions. Looks clean out of the box. Commented and :noslide: or :noexport: headings are filtered. Todos and tags are hidden.

The actual display is done in an indirect buffer. Your hooks and customizations for presentation will not pollute your editing buffer. Dirty state will not pile up in your presentation buffer, greatly increasing reliability even if your custom Elisp scripting is sloppy ๐Ÿ’ฉ.

Documents should "just work" and obtain decent results.

Actions add behavior to your content. They can be configured per-slide and in some cases per-element.

There are two kinds of actions:

To browse all actions, because they are all EIEIO classes, you can use eieio-browse and see the actions descend from dslide-action.

+--dslide-stateful-sequence
     +--dslide-action
          +--dslide-action-propertize
          +--dslide-action-image
          +--dslide-action-babel
          +--dslide-action-kmacro
          +--dslide-action-item-reveal
          +--dslide-action-hide-markup
          +--dslide-slide-action
               +--dslide-slide-action-every-child
               +--dslide-slide-action-inline
               +--dslide-slide-action-child
               +--dslide-slide-action-flat

Most actions are enabled by scanning for the right content. The babel action is used on babel blocks. The image action is used on image links. Some actions, especially slide actions, must be explicitly enabled. The markup used to enable actions can also be where they are configured.

Many actions understand configuration options, allowing tuning of similar behaviors from the same class.

๐Ÿ’ก To view an action's default values, call describe-symbol on it. Any slot definition usually has the same :initarg and will be understood when used in the configuration.

Configuring is usually done by adding plist-style :key value arguments after the class name, keyword, or affiliated keyword:

* A Headline For a Heading
:PROPERTIES:
# configuration after a class name
:DSLIDE_ACTIONS: dslide-action-item-reveal :inline t
:END:

# A keyword configuration
#+dslide_kmacro: :frequency 0.08 :jitter 0.5 :keys "M-x a n"

# An affiliated keyword configuration
#+attr_dslide_propertize: face '(:background "#ddddff")
This text will be propertized

๐Ÿšง After class names, the current plist read implementation splits the string rather than using read-string and is therefore not smart enough to parse lists as arguments. However dslide-action-propertize demonstrates doing this correctly and shows that it will be possible if needed.

You can write custom scripts into your presentation as Org Babel blocks. These are executed with the dslide-action-babel action. Easy peazy.

* My Heading With Babel Blocks
#+begin_src elisp
  (message "Good job!")
#+end_src

๐Ÿงช Experimental new feature. Hopefully the configuration argument names are good. Hopefully.

The dslide-action-kmacro will run pre-recorded sequences of keystrokes as if you are controlling the computer. Through :frequency and :jitter, it plays back strokes at a human-feeling pace.

Keyboard macros support :direction, but only forward and backward are recognized. Forward is the default.

By playing back keyboard macros, you can encode real Emacs workflows as steps in a presentation. Don't just talk about how your software works. Use the software with fully reproducible steps that users can understand in a tactile, human way.

To record kmacros as presentation steps, use the dslide-kmacro-transcribe-set-mark command. It will save a marker and every time you call kmacro-end-macro, it will transcribe that macro as an expression that dslide-action-kmacro knows how to play back.

๐Ÿ†’ The jitter uses a Laplace distribution to sample a perturbation power. This power is mapped onto the zero-to-infinity factor range by raising e to the power of jitter. This is multiplied by :frequency, which is a duration. As a result, while the jitter is usually pretty small, it does have some wild variation, which does look a bit more human.

Dslide uses a lot of markup that would not look good in a presentation. It also hides it by default using dslide-action-hide-markup. You can adjust the types using dslide-hide-markup-types

dslide-action-hide-markup will also hide todos and tags. You can modify this with dslide-hide-todo and dslide-hide-tags.

Use this when your headings are work-in-progress and you run out of time on Friday before the feature demo meeting. Have some content that is only not used in presentations? Use :noslide:.

To change the filtering from what is done by dslide-built-in-filter, customize dslide-default-filter or set DSLIDE_FILTER (possibly implemented ๐Ÿคก, file an issue!).

If dslide-header is configured, the keywords for the document title, email, and author etc will be used to generate an okay header.

#+,#+title:	Domain Specific sLIDEs
#+author:	Positron
#+email:	contact@positron.solutions

You can try customizing with dslide-header-email and similar variables or just set dslide-header-fun to completely replace the header with your own device. Check its signature!

Don't forget that if you need a customize variable only set in a particular presentation, you can use file local variables. Not every setting needs a keyword or babel block integration.

#+cindex confirming evaluation This is also one good way to set org-confirm-babel-evaluate and other settings that are somewhat risky to leave on generally.

# Local Variables:
# dslide-header: nil
# org-confirm-babel-evaluate: nil
# End:

How to control and view your presentation.

Presentations tend to be organized into a scripted linear sequence. We want to control the entire presentation sequence mostly with two buttons, forwards and backwards.

The controllers for presenting usually have very few buttons. Dslide was designed with this usage pattern in mind and can mostly be controlled by two commands.

Many controllers also have a "play" button or similar. It's recommended to map this to dslide-deck-start.

๐Ÿšง It is intended to overload dslide-deck-start further to implement "secondary" actions that can be triggered non-linearly.

There is likely no good place to bind dslide-deck-stop, but it's not critical. You can do everything with just three buttons.

Navigate your presentation faster when answering questions. The contents interface is a view of top-level headings. It overloads the presentation controls to navigate.

To enter the contents, call dslide-deck-start when a presentation is already active.

๐Ÿšง The start functions were recently overhauled. They need user feedback, both to identify bugs and focus on real uses cases. dslide-deck-start should be the most reliable way to start presentations.

The presentation you see is a cloned [indirect buffer](info:elisp#Indirect Buffers) of your org mode buffer. The Elisp state and overlays are independent. There are two key advantages:

Using comments and comment blocks, you can write down prompts or scripts to help you maintain your flow. Dslide highlights the current progress state, providing both debugging and narration feedback.

To leave a comment for yourself in the presentation source, just add a comment block or comment line:

# This is also a comment

#+begin_comment
This is a comment that only I can see while presenting, only when I look at my base buffer while sharing another frame.
#+end_comment

By default, the cursor is hidden in the presentation buffer using dslide-cursor-hide. Remove it from the dslide-start-hook to disable this. You can call dslide-cursor-restore if you just temporarily need a cursor.

Another good choice for interactive presentations is to use moc-subtle-cursor-mode from the Master of Ceremonies package. It is more like having a laser pointer that hides itself automatically.

Be sure to check M-x customize-group dslide to see all declared custom variables. All of the variables are configured to recommended defaults except hooks, which would depend on other packages usually.

Many settings can be configured at:

You likely want to start the mode via dslide-deck-start. Once the mode starts, it creates an indirect buffer to display the slides and then calls dslide-deck-start-function once the mode is active and everything is initialized, so you can customize startup behavior.

๐Ÿ’ก All top-level presentation commands begin with the dslide-deck prefix

(keymap-set org-mode-map "<f5>" #'dslide-deck-start)

Once the global minor mode, dslide-mode is active, additional bindings in dslide-mode-map are active in every buffer so that you can integrate other buffers into your presentation. (Tracking which buffers are part of a presentation is still a topic under consideration ๐Ÿšง)

Beware of using the normal dslide-mode-hook ๐Ÿ˜ฑ because it runs in the base buffer โš ๏ธ . If you use that hook to remap faces or add a bunch of styling, state will be copied to the indirect buffer but then linger in your base buffer. Instead, use dslide-start-hook. ๐Ÿ’ก

(defun my-stop-if-forward ()
  (dslide-push-step (lambda (direction)
                  (when (eq direction 'forward)
                    ;; Be sure to return t or the callback won't count as a
                    ;; step and the hook will run again.
                    (prog1 t (dslide-deck-stop))))))

(setq dslide-after-last-slide-hook #'my-stop-if-forward)

This is not unique to dslide, but if you want more professional looking results, you will likely need to make your org a bit prettier.

The setup used for the Positron's YouTube demos is not much more complex than this well-documented setup by System Crafters. Also see Prot's further documentation on customizing org mode faces and fonts.

In short, use:

Don't forget built-in emoji-search and searching insert-char.

Positron is cheating and also apply custom line-spacing and line-height. While Psionic maintains a custom org-modern, using custom spacing everywhere fights with visual-line-mode currently.

Creating new actions or replacing dslide classes.

Actions are the right choice when you need custom behavior that you want to re-use. Actions can be configured with arguments. They implement the stateful sequence lifecycle. For one-off solutions, you probably just want a babel block.

First choose your action type:

Override methods as appropriate, configure a heading to use your action, and you're done. Some actions, such as dslide-action-propertize only work when some of the section data is annotated.

The dslide-section-next and dslide-section-previous methods are very helpful behavior for quickly writing custom actions. They advance the action's :marker forwards and backwards to the next matching element and return that element so we can do something with it.

Example code:

(defclass dslide-action-red-paragraphs (dslide-action)
  ((overlays :initform nil))
  "Paint the paragraphs red, 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-red-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-red-paragraphs))
  (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 'error)
      (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-red-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))))))

The deck and slide class as well as actions can be sub-classed. Use the existing sub-classes of actions as example code for writing other classes. See the eieio#Top manual for explanation of OOP in Elisp.

This section provides really high-level summary of the code's major design choices to prepare for diving into source.

Org mode uses trees. Presentations are linear sequences. We can either traverse the tree or flatten it. Dslide chose to traverse. This design allowed implementing features such as dslide-slide-action-each-child. The children of such a parent slide exist simultaneously. A consequence of the choice not to flatten is that parents own their children. The lifecycle of a parent always encompasses its child.

Presentations are supposed to be linear sequences. We want to traverse the sequence, performing the steps, entirely by calling dslide-forward and dslide-backward.

If all sequences were idempotent, we would only implement dslide-forward and dslide-backward. However, sequences often require setup and teardown before carrying out a single step. This is the "stateful" part.

Implementing this without explicit setup methods crammed too much behavior into dslide-forward and dslide-backward while also requiring them to decide if they were attempting to make progress or just performing setup. It was annoying when building actions.

Setup and teardown can happen in both directions, so there is dslide-begin and dslide-end. The latter commonly calls the former and then advances the state to the end, but some more optimal setups are possible and already in use.

Slides may be disposed of after they no longer make progress. To allow intended cleanup to happen at the right moment, the parent calls dslide-final. This can be called at any time after dslide-end or dslide-begin.

The return values for these methods matter! See flow control.

Slides are created by calling dslide--make-slide with an org element for a heading. This function interprets the class name and arguments for the new slide and instantiates the object.

The default classes and actions can be configured at the document or customize level. Set the DSLIDE_DECK_CLASS and DSLIDE_SLIDE_CLASS as well as other properties that work at the heading level. The order of precedence (Not fully implemented ๐Ÿšง):

dslide--make-slide will look in order for the highest precedence setting and then instantiate the class with that value in the slot.

How various visual effects are achieved.

Org's Element API is the foundation on top of which dslide is built. It's documentation is not currently in a manual. Here's the web link: Org Element API docs. By using the element parser, we can avoid the issues that plague regex based implementations. (The trade-off is more garbage generation.)

Very frequently, we parse a section of the document and map over elements or headings within. This allows us to treat the document or a part of it as a list. The mapping functions all eventually delegate to dslide--map which itself uses org-element-map, narrowed to the targeted region.

It is very common when writing actions to work on only the section or only the children. For this reason, some shortcuts to map the section or children exist. Some section actions such as dslide-action-hide-markup are almost entirely built on dslide-section-map.

Frequently we are looking for an element before or after a marker, so shortcuts exist for finding the next or previous element. Section actions typically use dslide-section-next and dslide-section-previous. Slide actions typically use dslide-child-next and dslide-child-previous to traverse the child headings.

Mapping and progress tracking are intimately related. Finding the previous or next element is implemented by mapping to find the element beginning before or after a certain point. Careful handling of markers and a consistent scheme for sensing progress enable markers in the buffer to act as progress cursors for a variety of actions.

Dslide's predecessor, org-tree-slide, frequently used the point to track state. This can be fragile and there is also only one point. To be more robust when the document is changing out from under us, dslide uses markers.

Slides keep a reference to the heading in their :begin slot and then retrieve it using org-element-at-point. Actions similarly use a marker in order to keep track of how much of the current heading they have already used. For convenience, dslide-section-next and dslide-section-previous are used to simultaneously find the next element and update the marker, eliminating silly mistakes like forgetting to update the marker.

There are two schemes in place for tracking progress:

โš ๏ธ This section is fiddly and tricky. Put on your smarty hat. ๐Ÿ‘ท

Normal Progress

In short, find the element beginning after (before in reverse) the marker, move the marker to its beginning, and work on that element. If there is no next element, move as far as you can.

Reverse In Place Progress

If doing work means the next reverse step should undo that work, you need reversing in place. We need to slightly tweak our rules to allow two states on each element. Since every element ends after it begins, we can reliably use the end and beginning positions to differentiate if we already used an element when going forwards or backwards.

A very deliberate design choice was to avoid needing to return more than one element from a mapping call. This means we always want to find the element we intend to work on e.g. we do not want to find the element to work on and then have to find the next element to update the marker.

โ˜ข๏ธ Before these two schemes were developed, some actions were easier to implement one way while others were easier the other way. There was much flip-flopping and radiation sickness from broken actions. Eventually it was realized that both schemes make perfect sense for the right problems.

โš ๏ธ Org elements can and do overlap. Lists are one such challenge. List elements can all end at the same location. Naively calling org-element-at-point is a bad idea. See dslide-action-item-reveal for higher level interfaces.

If you need more states per element, this kind of implicit state tracking is insufficient and you will have to implement state-tracking. โš ๏ธ Don't use text properties to store state in buffer text since they will persist in the base buffer between presentation starts if not cleaned up.

These are some packages that are likely to find use alongside dslide.

Master of Ceremonies was written as a companion to dslide and was used in almost every single dslide demonstration video.

Bullets and many prettifications of common org markups. The markup that you don't hide looks better with org modern.

Never worry about turning on pretty links for a presentation. Edit them by just moving the point inside.

Open Broadcaster Software

Sacha Chua has written an OBS plugin integration helpful for video integration obs-websocket-el.

The moom package contains some commands for resizing text and repositioning frames.

Open issues and give feedback on feature requests. Contributions welcome. See the 1.0 feature roadmap.

This package is a direct descendant of Takaaki ISHIKAWA's org-tree-slide package. Many of the ideas and some of the implementations were either inherited or inspired by ideas from that package. This package would not exist without the inspiration. Thanks to everyone who contributed on org-tree-slide.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4