6

I'm writing a musical in collaboration with a composer. We're using org-mode, but neither of us is an expert. I'm using #+SRC blocks for occasional Lilypond code and #+VERSE blocks for lyrics, viz:

** SCENE II

description, dialogue, etc. description, dialogue, etc. description,
dialogue, etc. description, dialogue, etc. description, dialogue, etc.

#+NAME: song-name
#+BEGIN_VERSE
 la la la
 la la la
#+END_VERSE

#+NAME: song-name-melody
#+BEGIN_SRC lilypond :file song-name-melody.pdf
<< {
  /key d /major
  /time 3/4
  a4 a a |
  a4 a a |
 }

/addlyrics {
la la la |
la la la |
 }
>>
#+END_SRC

more description, dialogue, etc. description, dialogue, etc.
dialogue, etc. description, dialogue, etc. description, dialogue.

** SCENE III
etc.

I'd like my collaborator to be able to easily view just the lyrics, or just the Lilypond code. My first thought was to use TAGS or PROPERTIES, but because these blocks aren't headlines that doesn't seem possible.

How could this kind of narrowing (if that's the right term) be easily achieved?

  • 4
    I'll leave a substantive answer to those who can give one, but couldn't resist saying that I love that you're using Emacs to write a musical. – Dan Jul 25 '15 at 16:46
  • 2
    If it is ever produced, I'll post a note here! :) – Steven Arntson Jul 25 '15 at 20:40
  • What I understand is that you want to toggle between the source of musical notes and their renderings? What packages do you use in order to see musical notes in org-mode? Is there an external program that emacs uses to render musical notes inside org-mode? – Name Jul 26 '15 at 7:38
  • 1
    Looking at Org Element API should also be helpful. – Melioratus Dec 20 '15 at 20:45
  • 1
    Do you just want to see the elements, or do you also want to be able to edit them and have the edits back in the file? – John Kitchin Apr 26 '16 at 15:27
2

Here is a fairly long bit of code that uses invisibility to do what you want I think. There are two functions to hide non-verse and non-lilypad stuff, and two to show the non-verse/lilypad stuff. Basically it finds all those elements, and constructs invisible overlays and then removes them.

#+BEGIN_SRC emacs-lisp
(require 'cl)

; http://stackoverflow.com/questions/969067/name-of-this-function-in-built-in-emacs-lisp-library
(defun flatten (LIST)
  "flattens LIST"
  (cond
   ((atom LIST) (list LIST))
   ((null (cdr LIST)) (flatten (car LIST)))
   (t (append (flatten (car LIST)) (flatten (cdr LIST))))))

(defvar non-verse-overlays '() "overlays  to hide non-verse text")
(defvar non-lilypad-overlays '() "overlays  to hide non-lilypad blocks")

(defun hide-non-verse ()
  "Hide everything but the verse blocks."
  (interactive)
  ;; make sure we are wide open.
  (org-cycle '(64))
  (add-to-invisibility-spec '(non-verse-block . t))
  (let ((p (append
        (list (point-min))
        (flatten (org-element-map (org-element-parse-buffer) 'verse-block
               (lambda (vb) (list (org-element-property :begin vb)
                      (org-element-property :end vb)))))
        (list (point-max)))))

    (loop for start in p by 'cddr
      for end in (cdr p) by 'cddr
      do
      (let ((ov (make-overlay start end)))
        (add-to-list 'non-verse-overlays ov)
        (overlay-put ov 'invisible '(non-verse-block . t))))))

(defun show-non-verse ()
  "Show the non-verse"
  (interactive)
  (mapc 'delete-overlay non-verse-overlays)
  (setq non-verse-overlays '()))

(defun hide-non-lilypad ()
  "Hide everything but the verse blocks."
  (interactive)
  ;; make sure we are wide open.
  (org-cycle '(64))
  (add-to-invisibility-spec 'non-lilypad-block)
  (let ((p (append
        (list (point-min))
        (flatten (org-element-map (org-element-parse-buffer) 'src-block
               (lambda (sb)
             (when (string= "lilypond" (org-element-property :language sb))
               (list (org-element-property :begin sb)
                 (org-element-property :end sb))))))
        (list (point-max)))))

    (loop for start in p by 'cddr
      for end in (cdr p) by 'cddr
      do
      (let ((ov (make-overlay start end)))
        (add-to-list 'non-lilypad-overlays ov)
        (overlay-put ov 'invisible 'non-lilypad-block)))))

(defun show-non-lilypad ()
  (interactive)
  (mapc 'delete-overlay non-lilypad-overlays)
  (setq non-lilypad-overlays '()))
#+END_SRC
  • haven't gotten this working yet, but it looks promising, thank you! – Steven Arntson May 8 '16 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.