Atomでのforward searchとinverse search

最近はSyncTeXで、書いているTeX文章とプレビューア(SumatraPDFがメジャーだそうで)との間を行き来できるようにするのが流行りだそうですね。
ぼくはこの度メインのテキストエディタEmacsからAtomに移そうと画策していたのですが、inverse searchは簡単にできてもforward searchには結構手間取ったのでここに過程とか解決策を書いておこうと思います。まとめると、Windows上でテキストエディタとしてAtomを、プレビューアとしてSumatraPDFを使ったときのinverse searchとforward searchについて書きます。

Atomでinverse search

inverse searchは、プレビューアの文章のほうで選択した箇所に対応する
位置に、テキストエディタ上でジャンプする機能です。できたPDFを読んでいて「あ!誤字だ!」となったときに、対応する場所にテキストエディタ上で簡単にジャンプできて便利です。

これは、エディタにコマンドライン引数でファイルを指定して起動するときに、一緒に開く行数を指定すればいいだけなので簡単です。このとき、「それってファイルを二重に開いてしまうのでは」という気もして、実際そういうエディタもありますがAtomはデフォルトで今開いているファイルをアクティブにするようにできているようなので大丈夫でした。
この設定はSumatraPDFの側で行います。

1. まず、SumatraPDFで何か適当なSyncTeX対応のPDFファイルを開きます*1
2. 「設定」→「オプション」と画面を開きます。
3. 「逆順検索コマンドラインの設定」を開きます。もしもそのような項目がなければ、1の「SyncTeX対応の」を満たしていない可能性があります。SyncTeX対応にするには、LaTeXファイルのコンパイル時にオプションをつける必要があるので、http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?SyncTeXここで確認しましょう。
4. テキストボックスに「(Atomのパス)\atom.exe %f:%l」と入れます。Atomは「(ファイル名):(行番号)」で行を指定したファイルが開けるようです。AtomにPATHが通してあるならパスはわざわざ書かなくていいと思います。ぼくは「C:\Users\(ユーザ名)\AppData\Local\atom\app-0.187.0\atom.exe %f:%l」となりました。

これで完了です。SumatraPDF上でジャンプしたい箇所をダブルクリックすると、
それに対応した位置にAtom上でジャンプが起こります。

Atomでforward search

今度は逆に、テキストエディタから、対応する位置にPDF上でジャンプする機能です。あんまり使わないかもしれませんが、例えば「あるコマンドで書いてた数式を別の書き方をしてみた」というときに、その出来上がりを確認するとか…?

結論だけ言ってしまうと、sumatra-forwardsearchというAtom拡張を作ってみたのでよかったら使ってみてください。飛びたいところでコマンドパレットを開いて(Ctrl+Shift+P)「forwardsearch」というコマンドを叩けばOKです。その際、対応するPDFファイルをSumatraPDFで開いている必要があります。

forward searchは、プログラムと別のプログラムとの間で通信する仕組み*2としてWindowsが提供している超古代テクノロジーのDDE(Dynamic Data Exchange)を利用しています。SumatraPDFがDDEのために開放している窓口に、

[ForwardSearch("(TeXファイルのパス)",(行番号),(列番号),(新規ウインドウにするか),(フォーカスを合わせるか))]

というコマンドを送ればよいようです。これが超古代テクノロジーなのでDDEのコマンドを送る方法を探すのに大分難儀したのですが、NDdeという.Net用ライブラリがあって救われました。150DLぐらいしかありませんがサンプルもたっぷりついててとても使い易かったです。これで、

というC#のプログラムを書きました。DDE通信の部分は本当にこれだけです。あとはこのプログラムをAtomから呼び出してやればいいだけです。そのために、Atom拡張を書く羽目になりました。AtomCoffeeScript(JavaScriptの派生)+LESS(CSSの派生)+Node.JS(JSでブラウザ上に限らない「普通の」プログラムを書けるようにしたソフトウェアという認識でいる)で拡張します。
Web系の技術は移ろいが激しくて真剣に勉強する気になれなかったので、
CoffeeScript入門(前編) ― CoffeeScriptの基本構文 - Build Insiderを10分ぐらいで読んで、Atom
固有の拡張機能の書き方については3.1 Hacking Atom : Tools of the Tradeを読んで、チュートリアルをこなしてから書きました。バージョンアップが激しいので最新のを読むように気をつけましょう。結局Atomから外部のプログラムを起動したいので、メインは
Atomこれを使うことです。あとは現在のカーソルの行番号をAtom上で取得できればいいのですが、Atomチュートリアルの「Word Count」をこなしているうちに「atom.workspace.getActiveEditor()」でなんとかなるだろうという当たりがついて、
あとはAtomの「View→Developer→Toggle Developer Tools」で開ける
対話型のJSコンソールの入力補完をたよりにいろいろやってたらできました。
Atom開発をするときにここをうまく使うというのは1つコツになるでしょう。
基本的にDeveloper ToolsはChromeのやつなので、慣れてない人は
ChromeでDevelper Toolsを使いながらJSを触ってみるということをやってみるといいと思います。
ネット上にそういう記事が多分あると思います。
拡張自体はCoffeeScriptで書くのにコンソールではJSを書くというのは
結構いろいろやる羽目になって大変だなあという気はします。結局、

という風になりました。「__dirname」でこのスクリプトの位置が分かるというのは「Node.js カレントディレクトリ」でぐぐったんだったと思います。「Node.js (やりたいこと)」でぐぐるのも1つコツになりそうです。コンパイルした先のC#プログラムは、このcoffeeファイルと同じディレクトリに入れておきます。

あとはチュートリアル通りこれをコマンドで呼び出せるようにして完了になります。完成品はGithubashiato45/sumatra-forwardsearch · GitHubに置いてあるのでよかったら見てみてください。

参考文献

*1:というか「SyncTeXデータが同じディレクトリにある」と言うべきなのかもしれない

*2:プロセス間通信