Sphinx latex builder で長いファイルを literalinclude する

# 問題点

* 1ページを超えるソースコードを **code-block** や **literalinclude**  ディレクティブで配置. 
* さらに **caption** オプションを指定する.
* これを latexpdfja でビルド

この時

* ソースコードが適切に改行されない. 
* **caption** を指定しなければ一応問題ない
* sphinx 1.3.1 + python 3.4.3 + windows 10

# とりあえずの結論-Sphinx拡張, 並びに設定追加

code-block 並びに literalincude に caption がついた場合, 全体をfloatで囲わず, captionof(capt-of パッケージ) でキャプションを挿入する用に変更.
またそのために newfloat, needspaceパッケージを利用する. 最近のTeXLive, MikeTeXではこれらが標準で利用できるはず.

コードは, github (https://github.com/takaakiaoki/sphinx_latexnewfloat) に置きました.

# メモ

## 原因

検証した .rst ファイルは次の通り.

```rst
################################
Including long sourcecode
################################
   
literalinclude without caption
==================================

.. literalinclude:: bodeplot_lpf.m
   :language: Octave

literalinclude with caption
===================================

.. literalinclude:: bodeplot_lpf.m
   :language: Octave
   :caption: Caption
```

make pseudoxml とすると, このファイルから作られた .doctree を pseudoxml でわかりやすく出力する

```xml
<!-- 前略 -->
<section ids="including-long-sourcecode" names="including\ long\ sourcecode">
    <title>
        Including long sourcecode
    <section ids="literalinclude-without-caption" names="literalinclude\ without\ caption">
        <title>
            literalinclude without caption
        <literal_block highlight_args="{'linenostart': 1}" language="Octave" linenos="False" source="bodeplot_lpf.m" xml:space="preserve">
        <!-- ここからコード(省略) -->
<section ids="literalinclude-with-caption" names="literalinclude\ with\ caption">
    <title>
        <container classes="literal-block-wrapper" dupnames="caption" ids="caption" literal_block="True">
            <caption>
                Caption
            <literal_block highlight_args="{'linenostart': 1}" language="Octave" linenos="False" source="bodeplot_lpf.m" xml:space="preserve">
            <!-- ここからインクルードされたコード(省略) -->
```

とこのように, **\:caption\:** がつくことで **<container>, <caption>** タグが追加される.

これを受けて, latexのソースファイルは

```latex
% (前略)
\chapter{Including long sourcecode}
\label{code:welcome-to-latex-long-literalinclude-s-documentation}\label{code::doc}\label{code:including-long-sourcecode}

\section{literalinclude without caption}
\label{code:literalinclude-without-caption}
\begin{Verbatim}[commandchars=\\\{\}]
   %%% ここにインクルードされたコード(省略)
\end{Verbatim}
% 次のセクション
\section{literalinclude with caption}
\label{code:literalinclude-with-caption}
\begin{literal-block}
\caption{Caption}
\begin{Verbatim}[commandchars=\\\{\}]
   %%% ここにインクルードされたコード(省略)
\end{Verbatim}
\phantomsection\label{code:caption}
\end{literal-block}
   % (後略)
```

と外部に literal-block 環境(と caption)が追加される. この literal-block 環境は
sphinx.sty において,

```latex
% Define literal-block environment
\RequirePackage{float}
\floatstyle{plaintop}
\ifx\thechapter\undefined
  \newfloat{literal-block}{htbp}{loc}[section]
\else
  \newfloat{literal-block}{htbp}{loc}[chapter]
\fi
\floatname{literal-block}{List}
```

と float パッケージを用いて定義されている. この float 環境では改頁が行われない.    

## いい加減な回避方法

1. **caption** オプションをつけない

2. latexの場合にシンタックスハイライティングを行わない

```rst
.. only:: html

   .. literalinclude:: bodeplot_lpf.m
      :language: Octave
      :caption: Caption

.. only:: latex

   .. include:: bodeplot_lpf.m
      :literal:
```

## 回避方法, 改造

### newfloat, capt-of の利用

「float環境で改頁ができない」という問題については,
http://tex.stackexchange.com/questions/175650/how-to-allow-page-break-inside-a-float-environment において, capt-of 並びに newfloat パッケージを使うとよい, とのこと.
capt-of, newfloat 共に最近のTeXLiveに含まれているので, LaTeXの環境に手を入れる必要がない. 本来ならば, sphinx.sty で定義されている literal-block 環境をいったんリセットし, newfloat の DeclareFloatingEnvironment で再定義する方がよいが, よい方法が見つけられていない. 

```latex
% (前略)
%
% configure new literal-block-newfloat
\usepackage{newfloat}
\DeclareFloatingEnvironment[name={Listing}]{literal-block-newfloat}
% copy from sphinx.sty
\ifx\thechapter\undefined
  \SetupFloatingEnvironment{literal-block-newfloat}{within=section,placement=h}
\else
  \SetupFloatingEnvironment{literal-block-newfloat}{within=chapter,placement=h}
\fi
\usepackage{capt-of}
%
% (中略)
% 
% 次のセクション
\section{literalinclude with caption}
\label{code:literalinclude-with-caption}
\captionof{literal-block-newfloat}{Caption}
\begin{Verbatim}[commandchars=\\\{\}]
  %%% ここにインクルードされたコード(省略)
\end{Verbatim}
\phantomsection\label{code:caption}
% \end{literal-block}
% (後略)
```

### latex writer の改良

上記追加部分の \\usepackage 周辺は, conf.py の latex_elements['preamble'] を設定すれば良い. 一方, コード取り込み部分は, 

1. \\begin{literal-block} ... \\end{literal-block} を出力しない
2. \\caption{ ... } の代わりに \\captionof{literal-block-newfloat}{ ... } に置き換える.

この部分の出力は, 

* sphinx.writer.latex.LaTeXTranslator.visit_containar
* sphinx.writer.latex.LaTeXTranslator.depart_containar

で実施される.

```python:sphinx.writers.latex.py
def visit_container(self, node):
    if node.get('literal_block'):
        ids = ''
        for id in self.next_literal_ids:
            ids += self.hypertarget(id, anchor=False)
        if node['ids']:
            ids += self.hypertarget(node['ids'][0])
        self.next_literal_ids.clear()
        self.body.append('\n\\begin{literal-block}\n')
        self.context.append(ids + '\n\\end{literal-block}\n')

def depart_container(self, node):
    if node.get('literal_block'):
        self.body.append(self.context.pop())
```

これを見ると 1. は簡単に出来そう(実際できた). 2. は visit_caption, depart_caption で共通化されているので, "visit_caption ノードが visit_container 経由で呼ばれた場合は処理を変える" ことが必要になる(in_caption を参考に in_container_literal_block を追加).

## いろいろ感想

* なんかかんやで sphinx の簡単な拡張が書けた.
* \captionof 直後に改頁されるとダサいので, needspace パッケージにより\captionof を実行するために必要なスペースを確認する様にした. latexnewfloat_needspaceforcaption オプションがつくことに
* \captionof 直前のスペースが狭いので \vskip{0.5\baselineskip} を追加. このあたりはアドホックなのでおいおい調整
* literal-block-newfloat 環境初期化を conf.py のプリアンブルに記載するのはいまいち. writer か translator の中に入れるのが妥当. まだ builder translator writer の関係がよくわからない.