Emacs で LilyPond を使う (3) - スコアの一部だけを組版する

 長い曲を入力するとき、スコアの一部分だけを組版したいことがよくある。もちろん LilyPond にはそのための機能が用意されていて、showLastLength とか Score.skipTypesetting を使えばよいわけだが、実際のところ、不要な部分をコメントアウトしてしまった方が都合がいいこともある。コメントアウトしてしまえば、LilyPond が構文解析する手間を省けるし、エディタのシンタックスカラーリングを使えば編集時にも集中しやすい。そこで、Emacs Lisp でツールを作ることにした。

 作戦は次の通り。「% [数字]」というタイプのコメントをマーカー行として特別扱いして、こんな風にソースファイルを作っておく。

Violins = { % [1] violin-music1 % [2] violin-music2 % [3] violin-music3 } Cello = { % [1] cello-music1 % [2] cello-music2 % [3] cello-music3 }

 「セクション1-2を隠す」ときには、マーカー行を探してセクションを特定してコメント化する。

Violins = { % % [1] % violin-music1 % % [2] % violin-music2 % [3] violin-music3 } Cello = { % % [1] % cello-music1 % % [2] % cello-music2 % [3] cello-music3 }

 ただ、このままだと微妙な問題が起きる。僕は \relative をよく使うので、上の violin-musicN, cello-musicN はだいたい \relative c' { ... } というような形になっているのだが、スラーやタイがマーカー行をまたぐときには、別の \relative にするとつながってくれない。

\relative c' { c ( d e } % [2] \relative c' { f g ) } % 「終端されていないスラー」警告が出る

 そこで、ちょっとトリッキーな処理をすることにした。上のような場合は、% [2] の前の行の中カッコ(}) は閉じずにマーカー行の後ろに続きを書く。そして、マーカー行にダミーの \relative c' { を書いておく。

\relative c' { c ( d e % 中カッコを閉じない % [2] \relative c' { ←ダミーの \relative 命令 f g ) } % \relative c' を書かない

 セクション1をコメント化するときは、% [1] ... % [2]%{ [1] ... % [2] %} に置換する。そうすると、ダミーの \relative が有効になる(その前にブロックコメントが終了するため)。

Violins = { {% % [1] % \relative c' { ... % 中カッコを閉じない % [2] %} \relative c' { % ダミーの \relative が有効になる ... } % [3] violin-music3 }

 逆に、セクション2をコメント化するときは、% [2] ... % [3]} %{ [2] ... % [3] %} に置換する(%{ [2] の前に } を挿入してある)。これで、セクション1の中カッコはちゃんと閉じられる。

Violins = { % [1] \relative c' { ... % 閉じていない中カッコを、次の行先頭に挿入した } で閉じる } {% [2] \relative c' { % ダミー \relative はコメント内なので無効 % ... } % [3] %} violin-music3 }

 ちょっと凝り過ぎかな? もう少しシンプルに実現できそうな気もするけど、とりあえずはこの仕様で使ってみる。マーカー行をまたぐスラーがあるときは「終端されていないスラー」または「cannot end slur」警告が出るが、機械的な置き換えではここまで対応できないので、目をつぶることにする。

 上の例で、隠されるセクションの内容はブロックコメントになっているので、文法上は行頭に % を入れる必要はない。しかし、前にも書いた通り LilyPond emacs モードはブロックコメントを正しくカラーリングできないので、隠されたセクションが一目でわかるように行ごとにコメント化している。

 Emacs Lisp で実装してみた(→ lilypond_hide_section.el)。実際には lilypond-mode.el に書き入れてしまった。また、lilypond-mode.el のコードにも手を加えて、キーバインド (\C-ch) とメニューで使えるようにする。

(define-key LilyPond-mode-map "\C-cq" 'LilyPond-quick-insert-mode) (define-key LilyPond-mode-map "\C-c;" 'LilyPond-comment-region) (define-key LilyPond-mode-map "\C-ch" 'LilyPond-hide-sections) ;; Toshi Nagata (define-key LilyPond-mode-map ")" 'LilyPond-electric-close-paren) (define-key LilyPond-mode-map ">" 'LilyPond-electric-close-paren) ...(snip)... (easy-menu-define LilyPond-mode-menu LilyPond-mode-map "Menu used in LilyPond mode." (append '("LilyPond") '(["Add index menu" LilyPond-add-imenu-menu]) (list (cons "Insert tag" (cons ["Previously selected" LilyPond-insert-tag-current t] (cons "-----" (LilyPond-menu-keywords))))) '(("Miscellaneous" ["Autocompletion" LilyPond-autocompletion t] ["(Un)comment Region" LilyPond-comment-region t] ["Refontify buffer" font-lock-fontify-buffer t] "-----" ["Quick Insert Mode" LilyPond-quick-insert-mode :keys "C-c q"] ;; Toshi Nagata "-----" ["Hide/unhide numbered sections" LilyPond-hide-sections :keys "C-c h"] ;; End Toshi Nagata )) '(("Info" ["LilyPond" LilyPond-info t] ["LilyPond index-search" LilyPond-info-index-search t] ["Music Glossary" LilyPond-music-glossary-info t] ["LilyPond internals" LilyPond-internals-info t] )) ))

 メニューで LilyPond > Miscellaneous > Hide/unhide numbered sections を選ぶと、モード行に Sections to hide (like 1,2,3 or 1-3): と出るので、隠したいセクションを入力する。単にリターンを押すと、すべてのセクションが隠されなくなる。間違って呼び出してしまってキャンセルしたい場合は普通に C-g。なお、現在の実装ではダミーの \relative c' { を「行末に開き中カッコがあるかどうか」で判定しているので、上の説明のように \relative c' { のあとにコメントを置いてしまうとうまくいかない。要注意。

(2011/11/19 作成)