#+title: ffs: form feed-separated plain text presentations #+author: Amin Bandali #+email: bandali@gnu.org #+language: en #+options: ':t toc:nil author:t email:t num:t #+startup: content #+macro: stable-version 0.2.2 #+macro: release-date 2026-05-21 #+macro: development-version 0.2.3-git #+macro: kbd (eval (org-texinfo-kbd-macro $1)) #+texinfo_filename: ffs.info #+texinfo_dir_category: Emacs misc features #+texinfo_dir_title: FFS: (ffs) #+texinfo_dir_desc: Simple form feed-separated plain text presentations #+texinfo_header: @set MAINTAINERSITE @uref{https://kelar.org/~bandali/,maintainer webpage} #+texinfo_header: @set MAINTAINER Amin Bandali #+texinfo_header: @set MAINTAINEREMAIL @email{bandali@@gnu.org} #+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:bandali@@gnu.org,contact the maintainer} #+texinfo: @insertcopying This manual, written by Amin Bandali, introduces =ffs= and its user options, and provides every other piece of information pertinent to it. This manual corresponds to =ffs= stable version {{{stable-version}}}, released on {{{release-date}}}. Any reference to a newer feature which does not yet form part of the latest tagged commit is marked as such. Current development target is {{{development-version}}}. - Package name (GNU ELPA): [[https://elpa.gnu.org/packages/ffs.html][=ffs=]] - Official manual: - Change log: - Git repository: - Backronyms: fabulous foolproof slides - for freedom's sake - ffs flips slides Dedicated to the loving memory of [[https://kelar.org/~bandali/life/farangis.html][Farangis Yousefinia]]. #+toc: headlines 8 insert TOC here, with eight headline levels * COPYING :PROPERTIES: :COPYING: t :CUSTOM_ID: copying :END: Copyright \copy 2022--2026 Free Software Foundation, Inc. #+begin_quote Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being "A GNU Manual," and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled "GNU Free Documentation License." (a) The FSF's Back-Cover Text is: "You have the freedom to copy and modify this GNU manual." #+end_quote * Overview :PROPERTIES: :CUSTOM_ID: overview :END: This package provides a simple presentation mode which can be applied to any buffer for reading, writing, editing, and presenting slides. Slides are separated using the ~page-delimiter~, by default the =^L= character, known as the form feed, which can be inserted using {{{kbd(C-q C-l)}}}. Commands are provided for moving between those pages, aka slides. These motions work even when narrowing is in effect (and they preserve it). Through detailed explanations and concrete examples, this manual hopes to demonstrate that ~ffs~ is designed to be simple and flexible, and easy to use and extend. ffs does not define any global key bindings. You can define a key binding for ~ffs-mode~ in the ~global-map~ like so: #+begin_src elisp (global-set-key (kbd "C-c f s") #'ffs-mode) #+end_src On Emacs 29 or later, you can use the newer keymap functions, for instance: #+begin_src elisp (keymap-global-set "C-c f s" #'ffs-mode) #+end_src For convenience, ~ffs~ is provided as an alias for ~ffs-mode~. Once enabled, ~ffs-mode~ puts the buffer in read-only mode by setting ~buffer-read-only~, and provides convenient key bindings for moving between, editing, and inserting slides. These are available in the ~ffs-mode-map~ keymap. #+findex: ffs-present-mode #+vindex: ffs-default-face-height #+vindex: ffs-hide-cursor #+vindex: ffs-hide-mode-line #+vindex: ffs-hide-header-line When ready to present your slides, you can enable ~ffs-present-mode~, by default bound to the {{{kbd(s)}}} key in ~ffs-mode-map~ to start a presentation. Several user options are provided for customizing the appearance of the buffer during presentations, for using a different =height= for the ~default~ face (~ffs-default-face-height~), hiding the cursor (~ffs-hide-cursor~), hiding the mode line (~ffs-hide-mode-line~), and hiding the header line (~ffs-hide-header-line~). * Installation :PROPERTIES: :CUSTOM_ID: installation :END: ** GNU ELPA package :PROPERTIES: :CUSTOM_ID: installation-gnu-elpa :END: The package is available as =ffs=. Simply do: : M-x package-refresh-contents : M-x package-install And search for it. GNU ELPA provides the latest stable release. Folks who prefer to follow the development process in order to report bugs or suggest changes can use the version of the package from the GNU-devel ELPA. ** Manual installation :PROPERTIES: :CUSTOM_ID: installation-manual :END: Assuming your Emacs files are found in =~/.emacs.d/=, execute the following commands in a shell: #+begin_src sh # Make a directory for local lisp files and packages mkdir ~/.emacs.d/lisp # Go to the new directory cd ~/.emacs.d/lisp/ # Clone the ffs source repository git clone https://git.kelar.org/~bandali/ffs #+end_src Then, in your ~user-init-file~ (=init.el= or equivalent) add: #+begin_src emacs-lisp ;; Make Elisp files in the directory available (add-to-list 'load-path "~/.emacs.d/lisp/ffs") #+end_src Then restart your Emacs session or simply evaluate that expression (using {{{kbd(C-x C-e)}}}) so Emacs can find the package. On Emacs 31 or later, you can use the new User Lisp feature, where Emacs Lisp files in the directory specified by ~user-lisp-directory~ and its subdirectories will be recursively byte-compiled, scraped for autoload cookies, and ensured to be in ~load-path~. So all you need is to designate =~/.emacs.d/lisp/= as your ~user-lisp-directory~ in your ~early-init-file~ (=early-init.el=) like so: #+begin_src elisp (setq user-lisp-directory (locate-user-emacs-file "lisp/")) #+end_src * Sample configuration :PROPERTIES: :CUSTOM_ID: sample-config :END: #+cindex: Package configuration ~ffs~ tries to make as few opinionated choices as possible out-of-the-box, following the principle of least surprise. #+begin_src elisp (require 'ffs) ;; You can add a global key binding for enabling `ffs-mode'. (global-set-key (kbd "C-c f s") #'ffs-mode) ;; These user options apply when `ffs-present-mode' is enabled. ;; Their value is buffer-local. (setq-default ffs-hide-cursor t ffs-hide-mode-line t ffs-hide-header-line t) ;; You can add hooks to `ffs-mode-hook' or `ffs-present-mode-hook' for ;; hooks that are run every time `ffs-mode' or `ffs-present-mode' are ;; enabled and disabled. ;; The following sample hook is run when `ffs-present-mode' is enabled ;; and it disables `flyspell-mode', `show-paren-local-mode', and ;; `display-fill-column-indicator-mode', and re-enables them when ;; `ffs-present-mode' is disabled, to prevent visual distractions ;; from them during presentations. (add-hook 'ffs-present-mode-hook (lambda () (let ((arg (if ffs-present-mode -1 1))) (mapc (lambda (mode) (funcall mode arg)) '(flyspell-mode show-paren-local-mode display-fill-column-indicator-mode))))) ;; You can also add keys to `ffs-mode-map' for use when `ffs-mode' is ;; enabled. For keys that may be only relevant during presentations, ;; you can add them to `ffs-present-mode-map'. #+end_src * Default key bindings :PROPERTIES: :CUSTOM_ID: keybindings :END: This section documents the default key bindings of the various keymaps of ~ffs~. Care was taken to choose intuitive mnemonic-based keys for commands familiar from other existing similar keymaps, but you may override them if you so choose to. ** ~ffs-mode-map~ :PROPERTIES: :CUSTOM_ID: keybindings-ffs-mode-map :END: The ~ffs-mode-map~ is the main keymap of ~ffs-mode~, used both when preparing slides with ~ffs-mode~ enabled as well as while presenting them with ~ffs-present-mode~ enabled: | Command | Key binding(s) | |-------------------------------+--------------------------------------------------| | ~ffs-goto-previous~ | {{{kbd(p)}}}, {{{kbd(DEL)}}}, {{{kbd([)}}} | | ~ffs-goto-next~ | {{{kbd(n)}}}, {{{kbd(SPC)}}}, {{{kbd(])}}} | | ~ffs-goto-first~ | {{{kbd(<)}}} | | ~ffs-goto-last~ | {{{kbd(>)}}} | | ~ffs-start~ | {{{kbd(s)}}} | | ~ffs-stop-or-quit~ | {{{kbd(q)}}} | | ~ffs-edit~ | {{{kbd(e)}}}, {{{kbd(C-c ')}}} | | ~ffs-new-above~ | {{{kbd(O)}}} | | ~ffs-new-below~ | {{{kbd(o)}}} | | ~ffs-find-speaker-notes-file~ | {{{kbd(S)}}} | | ~narrow-to-page~ | {{{kbd(N)}}} | | ~widen~ | {{{kbd(W)}}} | | ~undo~ | {{{kbd(C-_)}}}, {{{kbd(C-/)}}}, {{{kbd(C-x u)}}} | | ~ffs-toggle-prefix-map~ | {{{kbd(t)}}} | | ~describe-mode~ | {{{kbd(?)}}} | ** ~ffs-present-mode-map~ :PROPERTIES: :CUSTOM_ID: keybindings-ffs-present-mode-map :END: The ~ffs-present-mode-map~ keymap used when ~ffs-present-mode~ is active (during presentations) inherits the key bindings of its parent keymap ~ffs-mode-map~, with the following changes: | Command | Key binding(s) | |--------------------+----------------| | ~ffs-stop-or-quit~ | {{{kbd(s)}}} | ** ~ffs-toggle-prefix-map~ :PROPERTIES: :CUSTOM_ID: keybindings-ffs-toggle-prefix-map :END: The ~ffs-toggle-prefix-map~ keymap, by default bound to {{{kbd(t)}}} in ~ffs-mode-map~, maps the following commands: | Command | Key binding(s) | |-------------------------------+----------------| | ~ffs-toggle-echo-progress~ | {{{kbd(e)}}} | | ~ffs-toggle-hide-cursor~ | {{{kbd(c)}}} | | ~ffs-toggle-hide-mode-line~ | {{{kbd(m)}}} | | ~ffs-toggle-hide-header-line~ | {{{kbd(h)}}} | | ~ffs-toggle-dark-mode~ | {{{kbd(d)}}} | ** ~ffs-edit-mode-map~ :PROPERTIES: :CUSTOM_ID: keybindings-ffs-edit-mode-map :END: The ~ffs-edit-mode-map~ keymap for ~ffs-edit-mode~ is used in ~ffs-edit~ buffers, when editing an existing slide or inserting a new one: | Command | Key binding(s) | |--------------------+--------------------| | ~ffs-edit-discard~ | {{{kbd(C-c C-k)}}} | | ~ffs-edit-done~ | {{{kbd(C-c C-c)}}} | * Acknowledgements :PROPERTIES: :CUSTOM_ID: thanks :END: #+cindex: Contributors ~ffs~ is meant to be a collective effort. Every bit of help matters and is greatly appreciated. - Author/maintainer :: Amin Bandali. - Contributions to code or the manual :: Protesilaos, Stefan Monnier. - Ideas and/or user feedback :: Protesilaos. ~ffs~ and its author owe a debt of gratitude to Protesilaos for rounds of code review and feedback for improving and polishing the package in preparation for submission to GNU ELPA. You can watch videos of these sessions on the author's website: - [[https://kelar.org/~bandali/gnu/emacs/ffs-code-review-prot.html][FFS code review with Protesilaos]] - [[https://kelar.org/~bandali/gnu/emacs/ffs-emacs-ext-prot.html][FFS code review and Emacs extensibility with Protesilaos]] Further, inspiration for parts of ~ffs~'s implementation was gratefully drawn from Protesilaos's [[https://protesilaos.com/emacs/logos][Logos]] package for Emacs. * GNU Free Documentation License :PROPERTIES: :APPENDIX: t :CUSTOM_ID: fdl :END: #+cindex: FDL, GNU Free Documentation License #+texinfo: @include fdl.texi * Indices :PROPERTIES: :CUSTOM_ID: indices :END: ** Function index :PROPERTIES: :INDEX: fn :CUSTOM_ID: indices-fn :END: ** Variable index :PROPERTIES: :INDEX: vr :CUSTOM_ID: indices-vr :END: ** Concept index :PROPERTIES: :INDEX: cp :CUSTOM_ID: indices-cp :END: * COMMENT Local Variables # Local Variables: # org-html-postamble-format: (("en" "
#

Org source

")) # End: