0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-11-10

問題点

  • 1ページを超えるソースコードを code-blockliteralinclude ディレクティブで配置.
  • さらに 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 ファイルは次の通り.

################################
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 でわかりやすく出力する

<!-- 前略 -->
<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: がつくことで , タグが追加される.

これを受けて, 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 において,

% 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の場合にシンタックスハイライティングを行わない

.. 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 で再定義する方がよいが, よい方法が見つけられていない.

% (前略)
%
% 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

で実施される.

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 の関係がよくわからない.
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?