macOSターミナルコマンドのマニュアルをiPadで見たい

まえがき

Macターミナルコマンドのマニュアルはmanコマンドで見ることができるけれども、 私はタブレットでないと長文を読むのが辛いのだ。
自分のMacのmanをブラウザで見ることができるようになればそれができる。

要件

manコマンドはmanファイルの内容を解釈して表示するものなので、 これをブラウザで読みやすいフォーマット(HTML)に変換して配信してくれるwebサーバを作れば良い。

man -> html 変換処理

Pythonは外部コマンドを実行できるので、利用できるなら外部コマンドを使って済ませる。

groffコマンドでmanファイルをhtmlに変換できる。

$ groff -Thtml -mandoc -c <manpath>

入力として与える”manpath”(manファイルのパス)は、

$ man -w <section> <command_name>

で得られる。

この”section”と”command_name”を受け取って、 変換したHTMLをレスポンスとして返すwebアプリ(サーバー)で目的を達成できる。

manserver

Python標準ライブラリにWSGIの簡易Webサーバーを提供するものがある。
WSGIであれば、URLからパラメータを取得して動的に結果を生成することができるので、 目的のWebアプリができる。

今回は簡単に

/section/command_name

として 必要なパラメータを受け付けることにする

ソースコード

#!/usr/bin/env python3
# coding: utf-8

# 外部コマンド実行
import subprocess
# WSGIサーバー
from wsgiref.simple_server import make_server


# 今回の WSGIアプリメイン
def app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/html; charset=utf-8')]

    # 'PATH_INFO' = /section/command_name
    path_info = environ['PATH_INFO'][1:].split('/')
    if len(path_info) != 2:
        return ['url: /section/command_name'.encode('utf-8')]

    ## man セクションは 1 から 9 なので、範囲外はセクション指定なし扱いとする
    section, command_name = path_info
    # invalid section
    if section not in ['{0}'.format(x) for x in range(1, 10)]:
        section = ''
    # invalid name
    if len(command_name) == 0:
        command_name = 'man'

    ret = ['command {0} not found in section {1}'.format(command_name, section).encode('utf-8')]

    ## subprocess.run で外部コマンド実行する。
    ## 今回のコマンドは標準出力に処理結果が出力される。それを使うためパイプをつなぐ。
    # manpath, man -w <section> <command_name>
    cp = subprocess.run(['man', '-w', section, command_name], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
    if cp.returncode == 0:
        manpath = cp.stdout.decode('utf-8').rstrip().lstrip()
        # man -> html, groff -Thtml -mandoc -c <manpath>
        cp = subprocess.run(['groff', '-Thtml', '-mandoc', '-c', manpath], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
        if cp.returncode == 0:
            html = cp.stdout.decode('utf-8')
            ret = [html.encode('utf-8')]

    start_response(status, headers)

    return ret


def main():
    with make_server('', 8080, app) as httpd:
        print('serving on port 8080...')
        httpd.serve_forever()


if __name__ == '__main__':
    main()

補足

まあ、アップルが用意したものがあるんですけどね。
Mac OS X Manual Pages


See also