Sphinx & reStructuredText入門~githubサンプルにもあるよ~

## この記事は
PDFなどのドキュメント生成ツールである[Sphinx](https://www.sphinx-doc.org/)の利用入門です。

テキストファイルからドキュメント生成するには[pandoc](https://pandoc.org/)などもありますが、ある程度大規模なドキュメント生成するにはpandocでは辛く、Sphinxが今の所お手軽さと自由度（できること）の幅がちょうど良いツールかなと思っています。

- macOSを対象に書いています。
- ドキュメント記述ルールは順次追記していきます。

## サンプル
以下に、実際にSphinxを利用してドキュメント記述し、
pdfとhtmlをビルドしてみたサンプルを置いています。

[https://github.com/sakaeda11/sphinx-study](https://github.com/sakaeda11/sphinx-study)

- 上のリポジトリの内容のビルド結果（github page）
  - pdf: [sphinx-study.pdf](https://sakaeda11.github.io/sphinx-study/latex/sphinx-study.pdf)
  - html: [index.html](https://sakaeda11.github.io/sphinx-study/html/source/)


> github actionでsphinxのインストール、ビルド、github pageへのデプロイを行っています。


## 基本手順
### 1.インストール
#### 1.1.sphinxのインストール

お手元のmacにbrewがインストールされていれば以下のコマンドで。

```:sphinxインストール
$brew install sphinx-doc
```

※インストール方法は他にもありますがここでは割愛

#### 1.2.mactex(mactex-no-gui)のインストール

Sphinxでpdfを出力するにはmactexが必要になるのでインストールします。

```:mactexインストール
$brew install --cask mactex-no-gui
```
(環境にも寄ると思いますが10〜20分ぐらいかかります)

→ここで私の環境では
`Error: Cask 'mactex-no-gui' conflicts with 'basictex'.`
と表示されインストール失敗。。

[macでtex環境を削除](https://qiita.com/tetsuo_jp/items/04a66b8f42946b5c5a5a)を参考にbasictexを削除してから再度mactex-no-guiのインストール実行しました。


mactexのインストール後、最新状態にアップデートします。

```:mactexアップデート
$sudo tlmgr update --self --all
```
※tlmgrはTeXのパッケージ管理ツール
こちらの処理も30分〜1時間ぐらいかかりました。


### 2.初期設定

以下のコマンドで初期セットアップを行います。
これを利用しない手順もあるにはあるのですが、面倒になるだけなので極力利用しましょう。

```:セットアップコマンド
$sphinx-quickstart
```

対話式で「パス、ディレクトリ設定、プロジェクト名、著者名、言語」などのが聞かれるので入力すると各種ファイルが作成されます。
ここで「`ソースディレクトリとビルドディレクトリを分ける(y/n)`」という選択肢が出てきますが、この記事では`y`を選択した前提で話を進めます。

設定すると以下のようなファイルとディレクトリが作成されます。

- **build/** : ビルド結果が置かれるディレクトリ
- **source/**
  - **_static/** : 画像などのリソースを置くディレクトリ
  - **_templates/** : 
  - **conf.py** : 設定ファイル
  - **index.rst** : ルートドキュメントファイル
- **make.bat** : makeビルド用ファイル（Windows用）
- **Makefile** : makeビルド用ファイル

### 3.ドキュメント記述

rstファイルを記述していきます。
この詳細は多岐に渡るので一旦デフォルトで生成される`index.rst`だけで次のビルドに進んでみましょう。
（ドキュメント記述の仕方は本ページの下の方に記載します。）

### 4.ビルド

※`sphinx-build`コマンドでビルドする方法と、sphinx-quickstartで生成されたMakefileを元に`make`コマンドでビルドする方法の2通りがありますが、基本は`make`を利用します。

```
$make [ビルダー]
```

ビルダーには色々ありますが、pdfを作成する場合は`latexpdf`を指定します

```:sh
$make latexpdf
```

すると`build/latex/`のディレクトリにプロジェクト名（sphinx-quickstartで指定したもの）のpdfファイルが生成されています。

## その他
### 設定ファイル（`conf.py`）

- sphinx-quickstartによって`source/conf.py`に作成される設定ファイル
- プロジェクト名や、著者名、各種拡張設定などが記述される
- python構文で記述されている
- 詳細は[Configuration](https://www.sphinx-doc.org/en/master/usage/configuration.html)を参照のこと

### Autodoc

- Sphinxではpythonのドキュメントを生成する機能も充実している
  - pythonソースコード上の`docstrings`というコメントを読み取ってドキュメント化してくれます。
  - 利用する場合はconf.pyに`extensions = ['sphinx.ext.autodoc']`と記述してこの機能を有効化する
  - [Intersphinx](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#module-sphinx.ext.intersphinx)という機能を利用すると、オンライン上のpythonドキュメントへのリンクを自動生成してくれる機能ももある
- 詳細は[Autodoc](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc)を参照のこと

### テーマ

- htmlを生成した際のデザインをテーマという形で設定できます
  - pdf生成時のデザイン変更はこの機能ではできません。[LaTeX customization
](https://www.sphinx-doc.org/en/master/latex.html)や[Options for LaTeX output
](https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-latex-output)を参照して設定して下さい。
- conf.pyの`html_theme`というパラメータにテーマを指定します
  - テーマには様々なものがあり、自身で作成することができます。
- 詳細は[HTML Theming](https://www.sphinx-doc.org/en/master/usage/theming.html)を参照のこと



# ドキュメント記述について(rstファイルの書き方)：[reStructuredText](https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html)
Sphinxでは基本的にreStructuredTextというファイル（拡張子rst）という書式でドキュメントを記述します。
このreStructuredTextは[Docutils](https://docutils.sourceforge.io/)によって提供されたものですが、これ元にSphinxでは独自の機能も追加して利用しています。

## 基本構文

→githubとgithub page上に随時書き足して行ってますのでそちらを参照して下さい。

[**github:sphinx-study**](https://github.com/sakaeda11/sphinx-study)
[PDF Sample](https://sakaeda11.github.io/sphinx-study/latex/sphinx-study.pdf)
[HTML Sample](https://sakaeda11.github.io/sphinx-study/html/)


## Directive（ディレクティブ）
ディレクティブはreStructuredTextを拡張するための機構

### Directiveのフォーマット

```
.. {ディレクティブタイプ}:: {パラメータ(オプション)}
   {パラメータ(オプション)}
   :
<空白行>
   {コンテンツ}
```

- ".. "とピリオド２つと半角スペースで始まる
- ディレクティブタイプは様々な物がある
    - 大文字小文字に区別はない
    - 1単語（スペースを含めない文字列）
- ディレクティブの後には":: "とコロン２つと半角スペースが続く
    - ディレクティブマーカーという
- ディレクティブマーカーの後や、次の行からはディレクティブタイプ次第
    - ディレクティブマーカーのパラメータやコンテンツになる
    - 次の行から記述されるパラメータはインデントで始まる
        - インデントの方式にはっきりした決まりは無いが、半角スペース3つで表現することが多い
    - コンテンツは、一行空白行を開けてから始まる

### 主なディレクティブ
#### toctree
> tocはTOC、Table of contentの略

rstファイルを分割して扱う場合に利用する

- 相対パスでも絶対パスでも指定できる
    - 相対パスは、そのファイルからの相対パス
    - 絶対パスはsourceディレクトリからのパスを示す
- 入れ子にできる
    - toctreeで埋め込まれたファイルの中で更にtoctreeを記述できる

- 出力フォーマットによって、リンクになるか、埋め込みになるかは異なる
    - HTMLなど複数ファイル形式の場合はリンク
    - PDFなどは埋め込み

### math

数式を記述するためのディレクティブ

```
.. math::

   (a + b)^2  &=  (a + b)(a + b) \\
              &=  a^2 + 2ab + b^2
```

### csv-table

テーブルの記述方法はいくつかありますが、ディレクティブを使った書き方は書きやすいです。

```
.. csv-table::

   a,b,c
   1,2,3
```

### todo & todolist

個人的に重宝しているのがこのディレクティブ
利用する際は先に以下のように`conf.py`に設定追記する必要があります。

```:conf.py
extensions = [
+  'sphinx.ext.todo',
]

+todo_include_todos = True
```

- estensionの追加
- todo_include_todosの有効化


その上で、rst上に

```
.. todo:: TODOの内容
```
と記述することで、TODOの枠が表示されます。
また、

```
.. todolist::
```
というディレクティブを記述すると、ドキュメント全体からtodoを探し出してリストアップしてくれます。


# 翻訳（i17n）
[参考：Sphinxで作る貢献しやすいドキュメント翻訳の仕組み](https://www2.slideshare.net/shimizukawa/sphinx-53764167)

ドキュメントの翻訳版を用意したい場合は以下の流れで行います。

## 0.事前準備

`sphinx-intl`のインストールと、`locale_dirs`の指定

```:sh
pip install sphinx-intl
```

```:conf.py
language = 'ja'

+locale_dirs = ['locale']
```

## 1.ドキュメントからpot（Potable Object Template）ファイルを生成します。

```:sh
make gettext
```

→`build/gettext` 以下にpotファイルが生成されます。

## 2.potファイルからlocaleディレクトリ以下に対象言語コードとしてのpoファイルを生成します

```:sh（日本語jaの場合）
sphinx-intl update -p build/gettext -l ja
```

→`{locale_dirs}/ja`以下にpoファイルが生成されます。


## 3.poファイルの対象の`msgid`に対する`msgstr`に翻訳ワードを記述します。

```:src.po（修正前、抜粋）
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:73
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:82
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:84
msgid "課題"
msgstr ""
```

↓

```:src.po（修正後、抜粋）
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:73
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:82
#: ../../src/chapter-1/chapter-1-1/2.基本的なドローンの構成.rst:84
msgid "課題"
msgstr "TODO"
```

## 4.pdfやhtmlをビルドします。

```:sh
make latexpdf
```

## 5.本文に更に変更があり、追加で翻訳していく場合は

`1` の`make gettext`から繰り返します。



## その他の設定

### PDFで空白ページを生成させない

Sphinxで生成されるPDFはデフォルトでは書籍をターゲットにしていて、適切に空白ページを入れ込みます。
便利な機能ですが、単にPDFとして生成したいときはこの空白ページは邪魔になります。

これを止めたい場合は`conf.py`に以下のように記述します。

```
latex_elements = {
  'extraclassoptions': 'openany'
}
```

以下の参考サイトでは `openany`だけではなく`openany,oneside`と書いてあったりしますが、`oneside`と書くことによる違いは今の所よく分かってません💦

[参考1:Sphinx docs: Remove blank pages from generated PDFs?](https://stackoverflow.com/questions/5422997/sphinx-docs-remove-blank-pages-from-generated-pdfs)
[参考2:Sphinx(latex→PDF)で余計な空白ページを消す方法](https://qiita.com/t2ru/items/c9f410bbaff1517a14e7)