; Given a groff lecture notes doc, turn it into a 32-pt lecture doc.
; This involves the following processing:
;    (1) Change the header to be 32 pt, and define slide macros.
;    (2) Do the clerical changing of groff commands, e.g., ".le" => ".lec"
;    (3) Slidify a lecture, by figuring out where page breaks should go.
;    (4) Provide an optional "animate" transform, that generates multiple
;        pages per slide, with each successive page adding the next item.
;    (5) Do some NLP to shorten phrases and sentences.
;
; As of 29mar11, only (2) is done.
;
;
; Some groff debugging stuff that may come in handy:
;  .tm \n[L1]
;  .tm \n[L\n[LL]]
;  .nr L\n[LL] -1
;  .af L\n[LL] I
;  .tm \n[L\n[LL]]
;
;
; 20jul11 Update: OK, it looks like the description under "Old Algorithm" below
; is pretty much a POS.  There are a number of problems, the most significant
; of which is that on non-continuing slides, the numbered top line needs to be
; preceded with a decrement of the enumerator reg, so the number stays the same
; as the lines are added one by one.  Have a look at the first couple slides in
; 101/lectures/slides/week1/all.me for a concrete example.
;
; I'm not exactly sure of the best approach to this problem.  One possibility
; is to focus on .(L X ... .)L X bracketed lists, rather than individual
; slides.  I'm not really sure that this will solve the problem with continuing
; vs non-continuing slides.  For that, some specific logic is most likely
; needed, including perhaps a parameterized function that takes as
; "is-continuing" parm.  One of the problems with the "Old Algorithm" may well
; be that I was trying to punk out and get something done in isolation, without
; having (all of) the necessary steps.
;
; What needs to happen is to go through a concrete lecture example and
; determine the different configurations for each slide, vis a vis slide
; animation.  The above-cited 101 week 1 slides are a pretty good example, with
; a number of varying slide formats.  A general solution strategy may go
; something like this: (1) clearly define each different configuration; (2)
; determine how to recognize a configuration from the content of a .bp-bounded
; slide; (3) write a slidifying function for each configuration, or one or more
; parameterized functions to do the slidification.
;
; Old Algorithm:
; 
; Animate a slide, bounded by ".bp" commands.  In terms of cursor starting
; position, "bounded by" means the slide to work on is determined as follows:
;
;    * If the cursor is on the "." of a ".bp", then the identified slide
;      extends from that .bp to the next .bp, or the end of the buffer if there
;      is no following .bp.
;
;    * If the cursor is not on the "." of a ".bp", then the identified slide is
;      that which is bounded by the immediately preceding .bp, and the
;      immediately following .bp, or end of buffer.
;
; Note that this requires a ".bp" in front of the first slide.  This is
; reasonable given the typical structure of slide presentations, with the first
; .bp after title page, which typically won't need to be animated.  If it does,
; we can stick an artificial .bp in front of it.  We might require a .bp after
; the last slide, but this is a bit funky, since it will put a blank page at the
; end of the presentation.  This actually may not be that bad, or even useful,
; since it will visually identify when we're done with a particular slide set.
; At this point, however, we have ".bp" or (eob) as legal end-of-slide
; delimiters.

; For the identified slide, start by adding a slide with just the header.  Then
; generate additional slides by adding each ".lec" or ".eec" delimited item to
; successive slides, until the full slide is reached.
;
(setq item-enumerator-re-search-string "^\\.lec\\|^\\.eec")
(setq slide-delim-search-string "^\\.bp\\|^\\.lcont")

(defun animate-slide()
    (interactive)    

    ; Narrow the buffer to the slide bounded above and below by ".bps", with
    ; eob being OK as the end bound if we're on the last slide.
    (narrow-buf-to-slide)

    ; Stick the whole slide in s, and stay at the beginning of the buffer.
    (end-of-buffer)
    (setq e (point))
    (beginning-of-buffer)
    (setq s (buffer-substring (point) e))

    ; While there are still items in s, stick in a copy of s, minus its last
    ; item.
    (setq items-left t)
    (while items-left
        ; Since I don't know how to do functional re search, we'll just stick
        ; in a copy of the buffer to do the re search, and if it fails, nuke
        ; the buffer we just stuck in.
        (insert s)
	(backward-char 1)
	(narrow-buf-to-slide)
	(end-of-buffer)

	; OK, we've stuck it in and we're sitting at the end.  Do the search,
        ; and if we find an item, nuke it.  If we find no item, nuke the whole
        ; itemless slide.
	(if (search-backward-regexp item-enumerator-re-search-string nil t)
          ; Find end of item by searching for first following groff command,
          ; and nuking the item
	  (progn
            (setq bi (point))
	    (forward-char 1)
	    (if (not (search-forward-regexp "^\\." nil t)) (end-of-buffer))
	    (beginning-of-line)
	    (kill-region bi (point))
	  )
          ; If no item, nuke the whole new slide buf, and set the loop guard to
          ; false.
          (progn
	    (beginning-of-buffer)
	    (setq b (point))
	    (end-of-buffer)
	    (kill-region b (point))
	    (setq items-left nil)
	  )
        )

        ; OK, we've nuked the last item, if there was one.  If in fact there
        ; was one, then stick the contents of the current narrowed buffer
        ; into s, and we'll go round again in the loop.
	(end-of-buffer)
	(setq e (point))
	(beginning-of-buffer)
	(setq s (buffer-substring (point) e))
    )

)

; Narrow the buffer to the region bounded by ".bp"s.  If we're on ".bp" line,
; consider this line to be the beginning of the slide.  Otherwise, the
; beginning of the slide is nearest preceding ".bp", or the beginning of buffer
; if there's no preceding ".bp".  The end of the slide is the nearest following
; ".bp", or the end of buffer if there's no following ".bp".
;
; When the narrowing is done, the upper .bp is there, the ending .bp is not.
; 
; Oh, and BTW, every place I've said ".bp" so far henceforth, I mean ``".bp" or
; ".lcont"'', which value is stored in slide-delim-search-string.
(defun narrow-buf-to-slide ()
    (interactive)

    ; Get the contents of the first three chars of the current line
    (beginning-of-line)
    (setq p (point))
    (forward-char 3)
    (setq l (buffer-substring p (point)))

    ; Check if we're on a ".bp" line.
    (if (or (string= l ".bp") (string= l ".lc"))

        ; Set b to the beginning of the .bp line, then go to the end for a
        ; clean search for the ending .bp.
	(progn
	    (setq b p)
	    (end-of-line)
        )

        ; If we're not on a ".bp" line, set b to the nearest preceding ".bp",
        ; or the beginning of the buffer if there's no preceding ".bp".  Do the
        ; end-of-line clean search thing again, as necessary.
        (if (search-backward-regexp slide-delim-search-string nil t)
	    (progn (setq b (point)) (end-of-line))
	    (setq b 0)
	)
    )

    ; Move to the next ".bp", or eob if none.
    (if (not (search-forward-regexp slide-delim-search-string nil t))
	(end-of-buffer)
	(beginning-of-line)
    )
    (narrow-to-region b (point))

    ; Finish up at the beginning of the slide buffer, for good measure.
    (beginning-of-buffer)
)

; Assume buffer has been narrowed to a slide.  Animate the chunk of items from
; point to eob.  Do this by inserting the region from the top of the buffer to
; point, followed by the contents of the end-list var.  At some point we could
; auto-gen the value of end-var by finding the begin-list groff command, but
; I've had enough of this hacking for now.
;
; To facilitate successive execution, move point to the next item enumerator,
; if any.
(defun animate-following-items ()
    (interactive)
    (setq p (point))
    (beginning-of-buffer)
    (setq b (point))
    (goto-char p)
    (insert (concat (buffer-substring b (point))))
    (end-of-line)
    (search-forward-regexp item-enumerator-re-search-string nil t)
    (beginning-of-line)
    (insert (concat end-list "\n"))
    (beginning-of-line)
)