From: Amin Bandali Date: Fri, 20 May 2022 01:57:45 +0000 (-0400) Subject: Add ffs (form feed slides) mode for GNU Emacs X-Git-Url: https://git.shemshak.org/~bandali/configs/commitdiff_plain/22758e8c9214f2086fe0c0a424c993f0a52a5780?hp=2176627ce01dff84926fb2b997779a223efe50e8 Add ffs (form feed slides) mode for GNU Emacs This is what I used for preparing and presenting my LibrePlanet 2022 talk, 'The Net beyond the web' back in March. :) --- diff --git a/.emacs.d/init.el b/.emacs.d/init.el index ce05ab4..11e4fb2 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -954,6 +954,21 @@ Effectively a very simple light/dark theme toggle switch." (with-eval-after-load 'emms (setq emms-directory (b/var "emms"))) +(add-to-list 'load-path (b/lisp "ffs")) +(run-with-idle-timer 0.5 nil #'require 'ffs) +(with-eval-after-load 'ffs + (global-set-key (kbd "C-c f s") #'ffs)) + +(defun b/export-frame () + (interactive) + ;; TODO: ask for fn and/or take as arg + (let* ((fn (make-temp-file "emacs" nil ".pdf")) + (data (x-export-frames nil 'pdf))) + (with-temp-file fn + (insert data)) + (kill-new fn) + (message fn))) + ;;; Post initialization diff --git a/.emacs.d/lisp/ffs/ChangeLog b/.emacs.d/lisp/ffs/ChangeLog new file mode 100644 index 0000000..41d87ca --- /dev/null +++ b/.emacs.d/lisp/ffs/ChangeLog @@ -0,0 +1,28 @@ +2022-03-09 Amin Bandali + + * ffsanim.el: Rename from ffs.el to ffsanim.el. Revision 0.1.5. + +2022-03-06 Amin Bandali + + * ffs.el (ffs-new-slide): Merge function into `ffs-edit-slide'. + Revision 0.1.4. + +2022-03-05 Amin Bandali + + * ffs.el: Implement insertion of new slide before or after the + current slide. Revision 0.1.3. + +2022-03-05 Amin Bandali + + * ffs.el (ffs-edit-mode): Change to a minor mode, and use the + source buffer's `major-mode' for the edit buffer. Revision 0.1.2. + +2022-03-05 Amin Bandali + + * ffs.el: Add `ffs-edit-mode' (derived from `text-mode') for the + new ffs-edit buffer for editing slides. Revision 0.1.1. + +2022-03-04 Amin Bandali + + * ffs.el: Initial revision 0.1.0. + diff --git a/.emacs.d/lisp/ffs/ffs.el b/.emacs.d/lisp/ffs/ffs.el new file mode 100644 index 0000000..99f2097 --- /dev/null +++ b/.emacs.d/lisp/ffs/ffs.el @@ -0,0 +1,419 @@ +;;; ffs.el --- Form Feed Slides mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Amin Bandali + +;; Author: Amin Bandali +;; Version: 0.1.0 +;; Keywords: outlines, tools + +;; 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 . + +;;; Commentary: + +;; A simple mode for doing simple plain text presentations where the +;; slides are separated using the form feed character ( ). + +;; Configuration: TODO + +;; Usage: + +;; Put this file, ffs.el, in a directory in your `load-path', then add +;; something like the following to your init file: +;; +;; (require 'ffs) +;; (global-set-key (kbd "C-c f s") #'ffs) + +;; Then, open a text file/buffer that you would like you to use as the +;; source of your presentation and type `M-x ffs RET' or a keyboard +;; shortcut you defined (like the above example) to start ffs, at +;; which point you should be able to see "ffs" appear as one of the +;; currently enabled minor modes in your mode-line. Once ffs is +;; enabled, you can invoke its various commands. To see a list of +;; available commands, you can either type `M-x ffs- TAB' (to get a +;; completion of commands starting with the "ffs-" prefix), or see the +;; definition of `ffs-minor-mode-map' near the end of this file. + +;;; Code: + +(defgroup ffs nil + "Minor mode for form feed-separated plain text presentations." + :version "29.1" + :prefix "ffs-") + +(defcustom ffs-default-face-height 370 + "The value of the `height' property for the `default' face to use +during the ffs presentation." + :group 'ffs + :type '(choice (const nil) + (integer :value 300))) + +(defcustom ffs-edit-buffer-name "*ffs-edit*" + "The name of the ffs-edit buffer used when editing a slide." + :group 'ffs + :type 'string) + +(defvar ffs--slides-buffer nil + "The main ffs presentation slides buffer. +When the user enables ffs in a buffer using `\\[ffs]', we store a +reference to that buffer in this variable. + +As a special case, in a speaker notes buffer selected by the user +using `\\[ffs-find-speaker-notes-file]' from the main ffs slides +buffer, this variable will point to the main ffs slides buffer +rather than the speaker notes buffer.") + +(defvar ffs--notes-buffer nil + "The ffs speaker notes buffer (only if selected). +When the user chooses (and opens) a speaker notes file using +`\\[ffs-find-speaker-notes-file]', a reference to the file's +corresponding buffer is stored in this variable, local to the +main ffs presentation slides buffer (`ffs--slides-buffer').") + +(defvar ffs--old-mode-line-format nil + "The old value of `mode-line-format' before enabling +`ffs--no-mode-line-minor-mode'.") + +(defvar ffs--old-cursor-type nil + "The old value of `cursor-type' before enabling +`ffs--no-cursor-minor-mode'.") + +(defvar ffs--old-default-face-height nil + "The old value of the `default' face's `height' property before +starting the ffs presentation.") + +(define-minor-mode ffs--no-mode-line-minor-mode + "Minor mode for hiding the mode-line." + :lighter nil + (if ffs--no-mode-line-minor-mode + (progn + (unless ffs--old-mode-line-format + (setq-local ffs--old-mode-line-format mode-line-format)) + (setq-local mode-line-format nil)) + (setq-local mode-line-format ffs--old-mode-line-format) + (when ffs--old-mode-line-format + ffs--old-mode-line-format nil)) + (redraw-display)) + +(define-minor-mode ffs--no-cursor-minor-mode + "Minor mode for hiding the cursor." + :lighter nil + (if ffs--no-cursor-minor-mode + (progn + (unless ffs--old-cursor-type + (setq-local ffs--old-cursor-type cursor-type)) + (setq-local cursor-type nil)) + (setq-local cursor-type ffs--old-cursor-type) + (when ffs--old-cursor-type + ffs--old-cursor-type nil))) + +(defun ffs--toggle-dark-mode () + "Swap the frame background and foreground colours." + (interactive) + (let ((bg (frame-parameter nil 'background-color)) + (fg (frame-parameter nil 'foreground-color))) + (set-background-color fg) + (set-foreground-color bg))) + +(defun ffs--goto-previous (buffer) + "Go to the previous slide in the given BUFFER." + (interactive) + (with-current-buffer buffer + (let ((n (buffer-narrowed-p))) + (when n + (goto-char (point-min)) + (widen) + (backward-page)) + (backward-page) + (when n (narrow-to-page))))) + +(defun ffs-goto-previous () + "Go to the previous slide in the main ffs presentation and the +speaker notes buffer (if any)." + (interactive) + (ffs--goto-previous ffs--slides-buffer) + (when ffs--notes-buffer + (ffs--goto-previous ffs--notes-buffer) + (redraw-display))) + +(defun ffs--goto-next (buffer) + "Go to the next slide in the given BUFFER." + (interactive) + (with-current-buffer buffer + (let ((n (buffer-narrowed-p)) + (e (= (- (point-max) (point-min)) 0))) + (when n + (goto-char (point-min)) + (widen)) + (unless e (forward-page)) + (when n (narrow-to-page))))) + +(defun ffs-goto-next () + "Go to the next slide in the main ffs presentation and the +speaker notes buffer (if any)." + (interactive) + (ffs--goto-next ffs--slides-buffer) + (when ffs--notes-buffer + (ffs--goto-next ffs--notes-buffer) + (redraw-display))) + +(defun ffs--goto-first (buffer) + "Go to the first slide in the given BUFFER." + (interactive) + (with-current-buffer buffer + (let ((n (buffer-narrowed-p))) + (when n (widen)) + (goto-char (point-min)) + (when n (narrow-to-page))))) + +(defun ffs-goto-first () + "Go to the first slide in the main ffs presentation and the +speaker notes buffer (if any)." + (interactive) + (ffs--goto-first ffs--slides-buffer) + (when ffs--notes-buffer + (ffs--goto-first ffs--notes-buffer) + (redraw-display))) + +(defun ffs--goto-last (buffer) + "Go to the last slide in the given BUFFER." + (interactive) + (let ((n (buffer-narrowed-p))) + (when n (widen)) + (goto-char (point-max)) + (when n (narrow-to-page)))) + +(defun ffs-goto-last () + "Go to the last slide in the main ffs presentation and the +speaker notes buffer (if any)." + (interactive) + (ffs--goto-last ffs--slides-buffer) + (when ffs--notes-buffer + (ffs--goto-last ffs--notes-buffer) + (redraw-display))) + +(defun ffs-start () + "Start the presentation." + (interactive) + (ffs-minor-mode 1) + (ffs--no-mode-line-minor-mode 1) + (ffs--no-cursor-minor-mode 1) + (when (integerp ffs-default-face-height) + (setq-local + ffs--old-default-face-height + (face-attribute 'default :height)) + (face-remap-add-relative + 'default :height ffs-default-face-height)) + (show-paren-local-mode -1) + (display-battery-mode -1) + (flyspell-mode -1) + (narrow-to-page)) + +(defun ffs-quit () + "Quit the presentation." + (interactive) + (let ((n (buffer-narrowed-p)) + (e (= (- (point-max) (point-min)) 0))) + (when (integerp ffs-default-face-height) + (face-remap-add-relative + 'default :height ffs--old-default-face-height)) + (show-paren-local-mode 1) + (display-battery-mode 1) + (flyspell-mode 1) + (ffs--no-mode-line-minor-mode -1) + (ffs--no-cursor-minor-mode -1) + (if n + (progn + (goto-char (point-min)) + (widen)) + (ffs-minor-mode -1)) + (when e (forward-char -1)))) + +(defun ffs-edit (&optional add-above-or-below) + "Pop to a new buffer to edit a slide. +If ADD-ABOVE-OR-BELOW is nil or not given, we are editing an +existing slide. Otherwise, if it is `add-above' then the new +slide will be added above/before the current slide, and if it is +`add-below' then the new slide will be added below/after the +current slide. The logic is implemented in `ffs-edit-done'." + (interactive) + (let* ((b (current-buffer)) + (m major-mode) + (n (buffer-narrowed-p)) + (s (if add-above-or-below ; if we are adding a new slide + "\n" ; start with just a newline + (unless n (narrow-to-page)) + (prog1 (buffer-string) + (unless n (widen)))))) + (pop-to-buffer-same-window + (get-buffer-create ffs-edit-buffer-name)) + (funcall m) + (ffs-edit-minor-mode 1) + (insert s) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (setq-local + ffs--edit-source-buffer b + ffs--new-location add-above-or-below) + (message + (substitute-command-keys "Edit, then use `\\[ffs-edit-done]' \ +to apply your changes or `\\[ffs-edit-discard]' to discard them.")))) + +(defun ffs-new-above () + "Add a new slide above/before the current slide." + (interactive) + (ffs-edit 'add-above)) + +(defun ffs-new-below () + "Add a new slide below/after the current slide." + (interactive) + (ffs-edit 'add-below)) + +(defun ffs-edit-discard () + "Discard current ffs-edit buffer and return to the presentation." + (interactive) + (let ((b (current-buffer))) + (quit-windows-on b) + (kill-buffer b))) + +(defun ffs-edit-done () + "Apply the ffs-edit changes and return to the presentation." + (interactive) + (let* (f + (str (buffer-string)) + (s (if (string-suffix-p "\n" str) + str + (concat str "\n"))) + (l ffs--new-location)) + (with-current-buffer ffs--edit-source-buffer + (let ((inhibit-read-only t)) + (save-excursion + (cond + ((eq l 'add-above) + (backward-page) + (insert (format "\n%s " s)) + (setq f #'ffs-previous-slide)) + ((eq l 'add-below) + (forward-page) + (insert (format "\n%s " s)) + (setq f #'ffs-next-slide)) + ((null l) + (narrow-to-page) + (delete-region (point-min) (point-max)) + (insert s) + (widen)))))) + (ffs-edit-discard) + (when (functionp f) + (funcall f)))) + +(defun ffs--undo (&optional arg) + "Like `undo', but it works even when the buffer is read-only." + (interactive "P") + (let ((inhibit-read-only t)) + (undo arg))) + +(defun ffs-find-speaker-notes-file (file) + "Prompt user for a speaker notes file, open it in a new frame." + (interactive "Fspeakers notes buffer: ") + (let ((b (current-buffer))) + (save-excursion + (find-file-other-frame file) + (ffs-minor-mode 1) + (setq-local + ffs--slides-buffer b + ffs--notes-buffer (current-buffer))) + (setq-local ffs--notes-buffer (get-file-buffer file)))) + +(defun ffs-export-slides-to-pdf () + (interactive) + (with-current-buffer ffs--slides-buffer + (ffs-goto-first) + (let ((c 1) + (fringe fringe-mode)) + (fringe-mode 0) + (while (not (eobp)) + (let ((fn (format "%s-%03d.pdf" + (file-name-sans-extension (buffer-name)) + c)) + (data (x-export-frames nil 'pdf))) + (with-temp-file fn + (insert data))) + (setq c (+ c 1)) + (ffs-goto-next)) + (fringe-mode fringe)))) + +(defvar ffs-edit-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-k") #'ffs-edit-discard) + (define-key map (kbd "C-c C-c") #'ffs-edit-done) + map) + "Keymap for `ffs-edit-minor-mode'.") + +(define-minor-mode ffs-edit-minor-mode + "Minor mode for editing a single ffs slide. +When done editing the slide, run \\[ffs-edit-done] to apply your +changes, or \\[ffs-edit-discard] to discard them." + :group 'ffs + :lighter " ffs-edit" + :keymap ffs-edit-minor-mode-map + (defvar-local ffs--edit-source-buffer nil + "The ffs presentation buffer of the slide being edited.") + (defvar-local ffs--new-location nil + "The location where the new slide should be inserted. +See the docstring for `ffs-edit' for more details.")) + +(defvar ffs-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "p") #'ffs-goto-previous) + (define-key map (kbd "n") #'ffs-goto-next) + (define-key map (kbd "DEL") #'ffs-goto-previous) + (define-key map (kbd "SPC") #'ffs-goto-next) + (define-key map (kbd "[") #'ffs-goto-previous) + (define-key map (kbd "]") #'ffs-goto-next) + (define-key map (kbd "<") #'ffs-goto-first) + (define-key map (kbd ">") #'ffs-goto-last) + (define-key map (kbd "s") #'ffs-start) + (define-key map (kbd "q") #'ffs-quit) + (define-key map (kbd "e") #'ffs-edit) + (define-key map (kbd "O") #'ffs-new-above) + (define-key map (kbd "o") #'ffs-new-below) + (define-key map (kbd "m") #'ffs--no-mode-line-minor-mode) + (define-key map (kbd "c") #'ffs--no-cursor-minor-mode) + (define-key map (kbd "d") #'ffs--toggle-dark-mode) + (define-key map (kbd "N") #'narrow-to-page) + (define-key map (kbd "W") #'widen) + (define-key map [remap undo] #'ffs--undo) + (define-key map (kbd "C-c n") #'ffs-find-speaker-notes-file) + map) + "Keymap for `ffs-minor-mode'.") + +(define-minor-mode ffs-minor-mode + "Minor mode for form feed-separated plain text presentations." + :group 'ffs + :lighter " ffs" + :keymap ffs-minor-mode-map + (setq-local + ffs--old-mode-line-format mode-line-format + ffs--old-cursor-type cursor-type + ffs--old-default-face-height + (face-attribute 'default :height)) + (setq buffer-read-only ffs-minor-mode)) + +(defun ffs () + "Enable `ffs-minor-mode' for presenting the current buffer." + (interactive) + (ffs-minor-mode 1) + (setq-local ffs--slides-buffer (current-buffer))) + +(provide 'ffs) +;;; ffs.el ends here diff --git a/.emacs.d/lisp/ffs/ffsanim.el b/.emacs.d/lisp/ffs/ffsanim.el new file mode 100644 index 0000000..cbf2969 --- /dev/null +++ b/.emacs.d/lisp/ffs/ffsanim.el @@ -0,0 +1,267 @@ +;;; ffsanim.el --- Form Feed Slides animate -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Amin Bandali + +;; Author: Amin Bandali +;; Version: 0.1.5 +;; Keywords: outlines, tools + +;; 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 . + +;;; Commentary: + +;; A simple mode for doing simple plain text presentations where the +;; slides are separated using the form feed character ( ). Uses +;; animate.el to animate each slide. + +;; Configuration: TODO + +;; Usage: + +;; (add-to-list 'load-path (b/lisp "ffs")) +;; (run-with-idle-timer 0.5 nil #'require 'ffsanim) +;; (with-eval-after-load 'ffsanim +;; (defvar b/original-default-height) +;; (defvar b/ffsanim-default-height 300) +;; (global-set-key +;; (kbd "C-c f s") +;; (lambda () +;; (interactive) +;; (setq +;; b/original-default-height (face-attribute 'default :height)) +;; (set-face-attribute +;; 'default nil :height b/ffsanim-default-height) +;; (message " ") +;; (ffsanim))) +;; (define-key +;; ffsanim-mode-map (kbd "q") +;; (lambda () +;; (interactive) +;; (quit-window) +;; (set-face-attribute +;; 'default nil :height b/original-default-height) +;; (message " ")))) + +;;; Code: + +(require 'animate) + +(defgroup ffsanim nil + "Major mode for form feed-separated plain text presentations." + :version "29.1" + :prefix "ffsanim-") + +(defcustom ffsanim-buffer-name "*ffsanim*" + "The name of the ffsanim presentation buffer." + :group 'ffsanim + :type 'string) + +(defcustom ffsanim-edit-buffer-name "*ffsanim-edit*" + "The name of the ffsanim-edit buffer used when editing a slide." + :group 'ffsanim + :type 'string) + +(defvar ffsanim--source-buffer-name "" + "The name of the form feed-separated \"source\" buffer for a +presentation.") + +(defun ffsanim--buffer () + "Get the ffsanim presentation buffer." + (get-buffer-create ffsanim-buffer-name)) + +(defmacro ffsanim-define-move-to-slide (name &optional doc &rest body) + "Define a function for moving to a slide. +Symbol NAME is the name describing the movement. +DOC is the documentation string to use for the function." + (declare (debug (&define name [&optional stringp] def-body)) + (doc-string 2) (indent defun)) + (when (and doc (not (stringp doc))) + ;; `doc' is the first element of `body', not an actual docstring + (push doc body) + (setq doc nil)) + (let* ((sn (symbol-name name)) + (fname (intern (format "ffsanim-%s-slide" (downcase sn))))) + `(defun ,fname () + ,doc + (interactive) + (let ((s (progn + (pop-to-buffer-same-window + (get-buffer ffsanim--source-buffer-name)) + ,@body + (narrow-to-page) + (prog1 (buffer-string) + (widen) + (pop-to-buffer-same-window (ffsanim--buffer))))) + (animation-buffer-name (buffer-name (ffsanim--buffer))) + (inhibit-read-only t)) + (animate-sequence (split-string s "\n") 0))))) + +(defun ffsanim-edit-slide (&optional add-before-or-after) + "Pop to a new buffer to edit a slide. +If ADD-BEFORE-OR-AFTER is nil or not given, we are editing an +existing slide. Otherwise, if it is `add-before' then the new +slide will be added before the current slide, and if it is +`add-after' then the new slide will be added after the current +slide. The logic for handling this is in `ffsanim-edit-done'." + (interactive) + (let* (m + (s (with-current-buffer (get-buffer ffsanim--source-buffer-name) + (setq m major-mode) + (if add-before-or-after ; if we are adding a new slide + "\n" ; start with just a newline + (narrow-to-page) + (prog1 (buffer-string) + (widen)))))) + (pop-to-buffer-same-window + (get-buffer-create ffsanim-edit-buffer-name)) + (funcall m) + (ffsanim-edit-mode 1) + (insert s) + (goto-char (point-min)) + (setq-local ffsanim--new-location add-before-or-after) + (message + (substitute-command-keys "Edit, then use `\\[ffsanim-edit-done]' \ +to apply your changes or `\\[ffsanim-edit-discard]' to discard them.")))) + +(defun ffsanim-edit-discard () + "Discard current ffsanim-edit buffer and return to the presentation." + (interactive) + (let ((buf (current-buffer))) + (quit-windows-on buf) + (kill-buffer buf)) + (pop-to-buffer-same-window (ffsanim--buffer))) + +(defun ffsanim-edit-done () + "Apply the ffsanim-edit changes and return to the presentation." + (interactive) + (let* (f + (str (buffer-string)) + (s (if (string-suffix-p "\n" str) + str + (concat str "\n"))) + (l ffsanim--new-location)) + (with-current-buffer (get-buffer ffsanim--source-buffer-name) + (save-excursion + (cond + ((eq l 'add-before) + (backward-page) + (insert (format "\n%s " s)) + (setq f #'ffsanim-previous-slide)) + ((eq l 'add-after) + (forward-page) + (insert (format "\n%s " s)) + (setq f #'ffsanim-next-slide)) + ((null l) + (narrow-to-page) + (delete-region (point-min) (point-max)) + (insert s) + (widen) + (setq f #'ffsanim-current-slide))))) + (ffsanim-edit-discard) + (funcall f))) + +(defun ffsanim-new-slide-before () + "Add a new slide before the current slide." + (interactive) + (ffsanim-edit-slide 'add-before)) + +(defun ffsanim-new-slide-after () + "Add a new slide after the current slide." + (interactive) + (ffsanim-edit-slide 'add-after)) + +(defvar ffsanim--old-mode-line-format nil + "The value of `mode-line-format' in the ffsanim presentation buffer +before the last call to `ffsanim--toggle-mode-line'.") + +(defun ffsanim--toggle-mode-line () + "Toggle the display of the mode-line in the current buffer." + (interactive) + (if mode-line-format + (setq-local ffsanim--old-mode-line-format mode-line-format + mode-line-format nil) + (setq-local mode-line-format ffsanim--old-mode-line-format + ffsanim--old-mode-line-format nil)) + (redraw-display)) + +(ffsanim-define-move-to-slide previous + "Go to the previous slide." + (backward-page) + (backward-page)) + +(ffsanim-define-move-to-slide next + "Go to the next slide." + (forward-page)) + +(ffsanim-define-move-to-slide current + "Reload and renimate the current slide." + nil) + +(ffsanim-define-move-to-slide first + "Go to the first slide." + (goto-char (point-min))) + +(ffsanim-define-move-to-slide last + "Go to the last slide." + (goto-char (point-max))) + +(define-derived-mode ffsanim-mode special-mode "ffsanim" + "Major mode for form feed-separated plain text presentations." + :group 'ffsanim + :interative nil + (setq-local animate-total-added-delay 0.3) + (show-paren-local-mode -1) + (display-battery-mode -1) + (ffsanim--toggle-mode-line) + (ffsanim-current-slide)) + +(defvar ffsanim-edit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-k") #'ffsanim-edit-discard) + (define-key map (kbd "C-c C-c") #'ffsanim-edit-done) + map) + "Keymap for `ffsanim-edit-mode'.") + +(define-minor-mode ffsanim-edit-mode + "Minor mode for editing a single ffsanim slide. +When done editing the slide, run \\[ffsanim-edit-done] to apply your +changes, or \\[ffsanim-edit-discard] to discard them." + :group 'ffsanim + :lighter " ffsanim-edit" + :keymap ffsanim-edit-mode-map + (defvar-local ffsanim--new-location nil + "The location where the new slide should be inserted. +See the docstring for `ffsanim-edit-slide' for more details.")) + +(define-key ffsanim-mode-map (kbd "p") #'ffsanim-previous-slide) +(define-key ffsanim-mode-map (kbd "n") #'ffsanim-next-slide) +(define-key ffsanim-mode-map (kbd "DEL") #'ffsanim-previous-slide) +(define-key ffsanim-mode-map (kbd "SPC") #'ffsanim-next-slide) +(define-key ffsanim-mode-map (kbd "g") #'ffsanim-current-slide) +(define-key ffsanim-mode-map (kbd "<") #'ffsanim-first-slide) +(define-key ffsanim-mode-map (kbd ">") #'ffsanim-last-slide) +(define-key ffsanim-mode-map (kbd "e") #'ffsanim-edit-slide) +(define-key ffsanim-mode-map (kbd "O") #'ffsanim-new-slide-before) +(define-key ffsanim-mode-map (kbd "o") #'ffsanim-new-slide-after) +(define-key ffsanim-mode-map (kbd "m") #'ffsanim--toggle-mode-line) + +(defun ffsanim () + "Start an ffsanim presentation with current buffer as source." + (interactive) + (setq ffsanim--source-buffer-name (buffer-name)) + (pop-to-buffer-same-window (ffsanim--buffer)) + (ffsanim-mode)) + +(provide 'ffsanim) +;;; ffsanim.el ends here