Browse Source

Add the ability to split the current window and show two slides at once

tags/v0.1.0
Peter J. Jones 6 years ago
parent
commit
2948e1fca5
2 changed files with 130 additions and 25 deletions
  1. 2
    1
      TODO.org
  2. 128
    24
      lisp/bufshow.el

+ 2
- 1
TODO.org View File

@@ -1,7 +1,8 @@
#+title: Bufshow To-do List

* Features that might be nice to have
** TODO Allow the file name to be a function in the slides vector
** DONE Allow the file name to be a function in the slides vector
CLOSED: [2012-11-28 Wed 09:41]
- Use `functionp` to figure this out
** TODO Allow the token to be a function in the slides vector
** TODO Allow the token to be a list of regular expressions

+ 128
- 24
lisp/bufshow.el View File

@@ -1,3 +1,4 @@
;;; -*- lexical-binding: t -*-
;;; bufshow.el -- A simple presentation tool for Emacs.
;;
;; Copyright (C) 2012 Peter Jones <pjones@pmade.com>
@@ -55,6 +56,8 @@ slides vector."
(defvar bufshow--slide-id 0)
(defvar bufshow--slide-vector [])
(defvar bufshow--dir nil)
(defvar bufshow--winconfig nil)
(defvar bufshow--restore-funcs nil)

;;; Interactive Functions
(defun bufshow-load (file)
@@ -95,9 +98,13 @@ lists. For example:
(\"file2\" \"token2\")])

This defines the order of slides. Each list in the vector should
contain the follow elements in order:
contain the following elements in order:

1. A file name relative to the current directory.
1. A string containing a file name relative to the current
directory. Instead of a string this element can be a
function, in which case the function will be called to show
a slide. Remaining elements in the list will be given to
the function as arguments.

2. This element is optional but if present controls how the
buffer will be narrowed. The default behavior is to locate
@@ -114,40 +121,136 @@ contain the follow elements in order:
It is recommended that you write an elisp file that contains a
call to this function with the slides vector then use
`bufshow-load' to evaluate this file and correctly set the base
directory. "
directory.

You can write your own functions for showing a slide as described
in item 1 above. Interesting functions provided by bufshow
include:

* `bufshow-split-below' and `bufshow-split-right'

If your function opens temporary buffers or needs to clean up
after itself you can add lambda expressions to be called after
the slide is changed by using `bufshow-add-clean-up-function'.

Your function will have to manually handle narrowing. You can
use the `bufshow-load-file' and `bufshow-show-token' functions to
perform the same loading and narrowing that bufshow does already.

When you are done with the presentation you can call
`bufshow-stop' to restore the window configuration and turn
`bufshow-mode' off."
(unless (vectorp slides) (error "slides should be a vector."))
(if (= (length slides) 0) (error "slides can't be empty."))
(setq bufshow--slide-id 0
bufshow--slide-vector slides
bufshow--dir (or bufshow--dir default-directory))
bufshow--dir (or bufshow--dir default-directory)
bufshow--restore-funcs nil
bufshow--winconfig (current-window-configuration))
(bufshow-activate-slide 0))

(defun bufshow-stop ()
"End the presentation and disable `bufshow-mode'."
(interactive)
(bufshow-reset)
(bufshow-mode -1))

(defun bufshow-split-below (file1 file2 &optional token1 token2)
"Split the current window into two windows, one above the
other. FILE1 should be the file to show in the top window and
FILE2 is the file to show in the bottom window. You can
optionally give TOKEN1 and TOKEN2 for narrowing FILE1 and FILE2
respectively.

If FILE1 and FILE2 are the same file an indirect buffer will be
created for the second window so that it can be narrowed
independently from the first."
(bufshow-split 'vertically file1 file2 token1 token2))

(defun bufshow-split-right (file1 file2 &optional token1 token2)
"Show two slides like `bufshow-split-below' except that they
are shown side-by-side."
(bufshow-split 'horizontal file1 file2 token1 token2))

(defun bufshow-add-clean-up-function (func)
"Call the function FUNC when the current slide is no longer
shown. This is useful for removing temporary buffers and/or
doing other useful clean up tasks.

You don't have to worry about the window configuration since that
will be restored automatically."
(add-to-list 'bufshow--restore-funcs func))

;;; Internal Functions
(defun bufshow-load-file (file)
"Load the given file into the current window. This also moves
point to the first line and removes any narrowing in preparation
for a call to `bufshow-show-token'."
(let* ((name (concat bufshow--dir file)))
(find-file name)
(widen)
(goto-char (point-min))))

(defun bufshow-show-token (token)
"Narrow to the given token."
(cond
((assoc major-mode bufshow-mode-functions)
(funcall (cdr (assoc major-mode bufshow-mode-functions)) token))
((assoc 'default bufshow-mode-functions)
(funcall (cdr (assoc 'default bufshow-mode-functions)) token))
(t (error "no bufshow mode function for this buffer."))))

(defun bufshow-activate-slide (n)
"Active slide number N."
(bufshow-restore)
(let* ((slide (aref bufshow--slide-vector n))
(file (car slide))
(token (cadr slide)))
(cond
((functionp file)
(apply file (cdr slide)))
(t
(bufshow-load-file file)
(if token (bufshow-show-token token))))))

(defun bufshow-split (direction file1 file2 &optional token1 token2)
"Split the window in the given direction and load FILE1 into
the first window and FILE2 into the second. If the files are the
same an indiect buffer will be created."
(bufshow-load-file file1)
(if token1 (bufshow-show-token token1))
(let* ((buf1 (current-buffer))
(win2 (if (eq direction 'vertically) (split-window-vertically)
(split-window-horizontally)))
buf2 uniq-name)
(with-selected-window win2
(if (not (string= file1 file2)) (bufshow-load-file file2)
(setq uniq-name (generate-new-buffer-name (buffer-name buf1))
buf2 (make-indirect-buffer buf1 uniq-name t))
(bufshow-add-clean-up-function (lambda () (kill-buffer buf2)))
(set-window-buffer nil buf2)))
(with-current-buffer buf2
(widen)
(goto-char (point-min))
(if token2 (bufshow-show-token token2)))))

(defun bufshow-reset ()
"Reset the internal bufshow variables to their defaults."
(bufshow-restore)
(setq bufshow--slide-id 0
bufshow--slide-vector []
bufshow--dir nil))

(defun bufshow-activate-slide (n)
"Active slide number N."
(let* ((slide (aref bufshow--slide-vector bufshow--slide-id))
(file (concat bufshow--dir (car slide)))
(token (cadr slide)))
(find-file file)
(widen)
(goto-char (point-min))
(if token
(cond
((assoc major-mode bufshow-mode-functions)
(funcall (cdr (assoc major-mode bufshow-mode-functions)) token))
((assoc 'default bufshow-mode-functions)
(funcall (cdr (assoc 'default bufshow-mode-functions)) token))
(t (error "no bufshow mode function for this buffer."))))))
(defun bufshow-restore ()
"Restore the previous window configuration and anything that
may have changed by a slide showing function."
(if bufshow--winconfig (set-window-configuration bufshow--winconfig))
(mapc 'funcall bufshow--restore-funcs)
(setq bufshow--restore-funcs nil))

(defun bufshow-narrow-to-org-id (token)
"Narrow the buffer to the org subtree whose ID is TOKEN."
(org-id-goto token)
(goto-char (org-find-entry-with-id token))
(org-narrow-to-subtree)
(org-show-subtree)
(run-hook-with-args 'org-cycle-hook 'subtree))
@@ -167,7 +270,7 @@ directory. "

;;;###autoload
(define-minor-mode bufshow-mode
"Bufshow mode is a presentation tool for Emacs. Enabling the
"Bufshow mode is a presentation tool for Emacs. Enabling this
global minor mode is the first step to using it. You'll also
need to define an elisp vector that contains the list of files
and tokens to use during the presentation and invoke
@@ -175,8 +278,8 @@ and tokens to use during the presentation and invoke

There are key bindings to move to the next and previous slides.
With an Emacs daemon and emacsclient it's easy to invoke the
`bufshow-next' and `bufshow-prev' functions from a remote using
something like lirc.
`bufshow-next' and `bufshow-prev' functions using an IR remote
and something like lirc.

\\{bufshow-mode-map}

@@ -188,6 +291,7 @@ For more information on how to configure a presentation see the
:global t
:keymap `((,(kbd "C-c <f9>") . bufshow-prev)
(,(kbd "C-c <f10>") . bufshow-next)
(,(kbd "C-c <f11>") . bufshow-load))
(,(kbd "C-c <f11>") . bufshow-load)
(,(kbd "C-c <f12>") . bufshow-stop))
;; Toggling the mode should clear the state variables.
(bufshow-reset))

Loading…
Cancel
Save