しばらく前にQuora
で、LaTeXで数学の講義ノートに遅れずについていく方法について質問に答えました。 そこで、VimとInkscape(図面用)を使用して、LaTeXでメモを取るワークフローを説明しました。 しかし、それ以来、多くのことが変わったため、新しいプロセスの説明を含むいくつかのブログ投稿を公開したいと思います。 これは最初の記事です。
私はLaTeXを使用して数学コースの第2学期にメモを取り始め、それ以来1700ページ以上を書きました。 概要がどのように見えるかの例を次に示します。
図面を含むこれらのメモは、講義で直接作成され、その後編集されません。 LaTeXで要約を効率的に書くには、4つのルールに従う必要があります。
- LaTeXでテキストと数式を書くことは、講師がボードに書くのと同じくらい速くなければなりません:遅延は受け入れられません。
- イラストの描画は、講師の描画とほぼ同じ速さでなければなりません。
- メモの管理、つまり、メモの追加、すべてのメモの整理、最後の2つの講義、メモの検索などは、すばやく簡単に行う必要があります。
- PDFドキュメントでメモを書きたい場合は、LaTeXを使用してPDFドキュメントに注釈を付けることができるはずです。
この記事は最初のポイントについてです:LaTeXでメモを取ること。
VimとLaTeX
LaTeXでテキストと数式を書くには、Vimを使用します。 これは強力な汎用テキストエディターであり、高度に拡張可能です。 私はそれを使って、コード、LaTeX、Markdownテキスト...一般に、あらゆるテキストを書きます。 彼はかなり急な学習曲線を持っていますが、ベースをマスターした場合、通常のホットキーなしでエディターに戻ることはすでに困難です。 これは、LaTeXドキュメントを編集したときの画面の外観です。
左側にVimがあり、右側に
ZathuraのPDFビューアーがあります。これはVimスタイルのキーボードショートカットもサポートしています。 私はUbuntuで
bspwmウィンドウマネージャーを使用しています。 プラグインとしてLaTeXは
vimtexをインストールし
ました 。 構文の強調表示、目次、synctexなどを提供します。vim
-plugを使用して、次のように構成しました。
Plug 'lervag/vimtex'
let g:tex_flavor='latex'
let g:vimtex_view_method='zathura'
let g:vimtex_quickfix_mode=0
set conceallevel=1
let g:tex_conceal='abdmg'
最後の2行は変装を調整します。 これは、カーソルがこの行にないときにLaTeXコードが置き換えられるか、非表示になる関数です。
\ [
、
\]
、
$
を非表示にすると、それほど目立たなくなり、ドキュメントの概要がわかりやすくなります。 この関数は、アニメーションに示すように、
\bigcap
withに、
\in
を
∈
などに置き換えます。
この設定を使用すると、講師がボードに書き込むのと同じ速さでLaTeXに書き込むというタスクを達成できます。 ここでスニペットが機能します。
スニペット
スニペットとは何ですか?
スニペットは、他のテキストによって呼び出される再利用可能な短いテキストです。 たとえば、記号を入力してTabキーを押すと、単語signは署名に変わります。
スニペットは動的にすることができます。
today
入力し
today
Tab
と、
today
の単語は現在の日付に置き換えられ、
box
-
Tab
は自動的にサイズが大きくなるフィールドになります。
あるスニペットを別のスニペット内で使用することもできます。
UltiSnipsを使用したスニペットの作成
スニペットを制御するには、
UltiSnipsプラグインを使用します。 その構成は次のとおりです。
Plug 'sirver/ultisnips' let g:UltiSnipsExpandTrigger = '<tab>' let g:UltiSnipsJumpForwardTrigger = '<tab>' let g:UltiSnipsJumpBackwardTrigger = '<s-tab>'
スニペット
sign
コード:
snippet sign "Signature" Yours sincerely, Gilles Castel endsnippet
動的スニペットの場合、逆引用符の間にコードを挿入できます。このコードは、スニペットが拡張されるときに実行されます。 ここでは、bashを使用して現在の日付をフォーマットしました:
date + %F
snippet today "Date" `date +%F` endsnippet
`!p ... `
ブロック内で、Pythonで記述できます。
box
スニペットのコードを見てください:
snippet box "Box" `!p snip.rv = '┌' + '─' * (len(t[1]) + 2) + '┐'` │ $1 │ `!p snip.rv = '└' + '─' * (len(t[1]) + 2) + '┘'` $0 endsnippet
このコードの代わりに、
snip.rv
変数の値がドキュメントに挿入されます。 ブロック内では、スニペットの現在の状態にアクセスできます。たとえば、
t[1]
は最初のタブの場所に対応し、
fn
現在のファイル名などに対応します。
LaTeXスニペット
スニペットは、特に一部のより複雑なスニペットの作業を大幅にスピードアップします。 最も単純なものから始めましょう。
環境
環境を挿入するには、行の先頭に
beg
と入力するだけです。 次に、環境の名前。これは
\end{}
コマンドに反映されます。
Tab
キーを押すと、カーソルが内部に配置されます。
コードは次のとおりです。
snippet beg "begin{} / end{}" bA \begin{$1} $0 \end{$1} endsnippet
b
記号は、このようなスニペットが行の先頭でのみ機能
A
ことを意味します
A
は自動拡張を意味します。つまり、
Tab
を押す必要はありません。
Tab
と
Shift
+
Tab
Tab
を押して移動する
Tab
は
$1
、
$2
、...と表示され、後者は
$0
と表示され
$0
。
インライン式と表示式
最も一般的に使用される2つのスニペットは、数学モードをトリガーする
mk
と
dm
です。 1つ目はインライン式、2つ目は表示された式です。
式スニペットはスマートです。彼は、ドル記号の後にスペースを挿入するタイミングを知っています。 終了$の直後に単語の入力を開始すると、スペースが追加されます。 しかし、別の文字を入力しても、「$ p $ -value」の場合のようにスペースは追加されません。
このスニペットのコードは次のとおりです。
snippet mk "Math" wA $${1}$`!p if t[2] and t[2][0] not in [',', '.', '?', '-', ' ']: snip.rv = ' ' else: snip.rv = '' `$2 endsnippet
最初の行の末尾にある
W
は、スニペットが単語の境界でのみ拡張されることを意味します。 したがって、たとえば、
hellomk
は機能せず、
hello mk
は機能します。
表示される数式のスニペットは単純ですが、非常に便利です。 方程式は常にドットで終了します。
<snippet dm "Math" wA \[ $1 .\] $0 endsnippet
下付き文字と上付き文字
別の便利なスニペットはインデックス用です。
a1
を
a_1
、
a_12
を
a_{12}
ます。
このスニペットのコードは、正規表現をトリガーとして使用します。
[A-Za-z]\d
としてエンコードされた文字が続く文字、または
_
と2つの数字が続く文字を入力すると、フラグメントが展開されます:
[A-Za-z]_\d\d
snippet '([A-Za-z])(\d)' "auto subscript" wrA `!p snip.rv = match.group(1)`_`!p snip.rv = match.group(2)` endsnippet snippet '([A-Za-z])_(\d\d)' "auto subscript2" wrA `!p snip.rv = match.group(1)`_{`!p snip.rv = match.group(2)`} endsnippet
(\d\d)
などの括弧を使用して正規表現の一部をグループに結合する場合、Pythonの
match.group(i)
介してスニペット拡張で使用できます。
上付き文字については、
^{}
変わる
td
を使用します。 最も一般的なもの(正方形、立方体、その他いくつか)では、
sr
、
cb
、
comp
などの個別のスニペットが意図されています。
snippet sr "^2" iA ^2 endsnippet snippet cb "^3" iA ^3 endsnippet snippet compl "complement" iA ^{c} endsnippet snippet td "superscript" iA ^{$1}$0 endsnippet
分数
最も便利なスニペットの1つは、分数で機能します。 彼は次の置換を行います。
//
→
\frac{}{}
3/
→
\frac{3}{}
4\pi^2/
→
\frac{4\pi^2}{}
(1 + 2 + 3)/
→
\frac{1 + 2 + 3}{}
(1+(2+3)/)
→
(1 + \frac{2+3}{})
(1 + (2+3))/
→
\frac{1 + (2+3)}{}
最初の簡単なコード:
snippet // "Fraction" iA \\frac{$1}{$2}$0 endsnippet
2番目と3番目の置換は、式
3/
、
4ac/
、
6\pi^2/
、
a_2/
などに対応する正規表現を使用して行われます。
snippet '((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/' "Fraction" wrA \\frac{`!p snip.rv = match.group(1)`}{$1}$0 endsnippet
ご覧のとおり、正規表現は非常に長くなる可能性がありますが、すべてを説明する図を次に示します。
4番目と5番目のケースでは、スニペットは対応するブラケットを見つけようとします。 UltiSnips正規表現エンジンはこれを行う方法を知らないため、Pythonを使用する必要がありました。
priority 1000 snippet '^.*\)/' "() Fraction" wrA `!p stripped = match.string[:-1] depth = 0 i = len(stripped) - 1 while True: if stripped[i] == ')': depth += 1 if stripped[i] == '(': depth -= 1 if depth == 0: break; i -= 1 snip.rv = stripped[0:i] + "\\frac{" + stripped[i+1:-1] + "}" `{$1}$0 endsnippet
最後に、現在の選択を分数に変換するスニペットを共有したいと思います。 テキストを選択し、
Tab
押して
/
、もう一度
Tab
ます。
コードは、選択を反映する
${VISUAL}
変数を使用します。
snippet / "Fraction" iA \\frac{${VISUAL}}{$1}$0 endsnippet
SympyとMathematica
別のクールですが、あまり使用されていないスニペットは、
sympyを実行して
数式を評価します。 例:
sympy
Tab
は
sympy | sympy
展開され
sympy | sympy
sympy | sympy
および
sympy 1 + 1 sympy
Tab
は
2
ます。
snippet sympy "sympy block " w sympy $1 sympy$0 endsnippet priority 10000 snippet 'sympy(.*)sympy' "evaluate sympy" wr `!p from sympy import * x, y, z, t = symbols('xyz t') k, m, n = symbols('km n', integer=True) f, g, h = symbols('fg h', cls=Function) init_printing() snip.rv = eval('latex(' + match.group(1).replace('\\', '') \ .replace('^', '**') \ .replace('{', '(') \ .replace('}', ')') + ')') ` endsnippet
Mathematicaでは、同様のことが可能です:
priority 1000 snippet math "mathematica block" w math $1 math$0 endsnippet priority 10000 snippet 'math(.*)math' "evaluate mathematica" wr `!p import subprocess code = 'ToString[' + match.group(1) + ', TeXForm]' snip.rv = subprocess.check_output(['wolframscript', '-code', code]) ` endsnippet
後置スニペット
特定の文字を入力した後に適切なテキストを挿入する接尾辞スニペットも言及する価値があります。 たとえば、
phat
→
\hat{p}
および
zbar
→
\overline{z}
。 同様のスニペットは、
v,.
などのベクトルを挿入し
v,.
→
\vec{v}
および
v.,
→
\vec{v}
ピリオドとセミコロンの順序は重要ではないため、同時にクリックできます。 これらのスニペットは、講師がボードに書き込む速度と同じ速度で入力するため、時間を節約できます。
優先順位が低い場合にのみ、
bar
と
hat
プレフィックスが機能することに注意してください。 これらのスニペットのコードは次のとおりです。
priority 10 snippet "bar" "bar" riA \overline{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])bar" "bar" riA \overline{`!p snip.rv=match.group(1)`} endsnippet
priority 10 snippet "hat" "hat" riA \hat{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])hat" "hat" riA \hat{`!p snip.rv=match.group(1)`} endsnippet
snippet "(\\?\w+)(,\.|\.,)" "Vector postfix" riA \vec{`!p snip.rv=match.group(1)`} endsnippet
その他のスニペット
私はまだ一般的に使用されるスニペットを約100個持っています。 それらはすべて
ここから入手でき
ます 。 それらのほとんどは非常に単純です。 たとえば、
!>
は
\mapsto
、
->
は
\to
になります。
fun
f: \R \to \R :
に変換し
f: \R \to \R :
、
!>
→
\mapsto
、
cc
→
\subset
。
lim
は
\lim_{n \to \infty}
、
sum
→
\sum_{n = 1}^{\infty}
、
ooo
→
\infty
ます。
コース固有のスニペット
頻繁に使用されるものに加えて、特定のスニペットもあります。 これらは、
.vimrc
単一行としてロードされ
.vimrc
。
set rtp+=~/current_course
ここで、
current_course
は現在のコースへの
シンボリックリンクです (これについては別の記事で詳しく説明します)。 このフォルダーには
~/current_course/UltiSnips/tex.snippets
というファイルがあり、ここにコーススニペットを追加します。 たとえば、量子力学の場合、燭台とケトの量子状態を記録するスニペットがあります。
<a|
→
\bra{a}
<q|
→
\bra{\psi}
|a>
→
\ket{a}
|q>
→
\ket{\psi}
\braket{a}{b}
→
\braket{a}{b}
量子力学では多くの場合
\psi
使用するので、braketのすべての
q
を
\psi
に自動的に置き換えました。
snippet "\<(.*?)\|" "bra" riA \bra{`!p snip.rv = match.group(1).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet snippet "\|(.*?)\>" "ket" riA \ket{`!p snip.rv = match.group(1).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet snippet "(.*)\\bra{(.*?)}([^\|]*?)\>" "braket" riA `!p snip.rv = match.group(1)`\braket{`!p snip.rv = match.group(2)`}{`!p snip.rv = match.group(3).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet
コンテキスト
これらのスニペットを書くときは、プレーンテキストで見つかるかどうかを検討する必要があります。 たとえば、私の辞書によると、英語には約72語、オランダ語にはsrの2,000語があります。 したがって、「
disregard
」と入力すると、
sr
が
^2
に変わり、
di^2egard
ます。
この問題の解決策は、スニペットにコンテキストを追加することです。 Vimの構文の強調表示は、数式モードかテキストモードかによって、UltiSnipsがスニペットを使用するかどうかを決定します。 私はこのオプションを思いつきました:
global !p texMathZones = ['texMathZone'+x for x in ['A', 'AS', 'B', 'BS', 'C', 'CS', 'D', 'DS', 'E', 'ES', 'F', 'FS', 'G', 'GS', 'H', 'HS', 'I', 'IS', 'J', 'JS', 'K', 'KS', 'L', 'LS', 'DS', 'V', 'W', 'X', 'Y', 'Z']] texIgnoreMathZones = ['texMathText'] texMathZoneIds = vim.eval('map('+str(texMathZones)+", 'hlID(v:val)')") texIgnoreMathZoneIds = vim.eval('map('+str(texIgnoreMathZones)+", 'hlID(v:val)')") ignore = texIgnoreMathZoneIds[0] def math(): synstackids = vim.eval("synstack(line('.'), col('.') - (col('.')>=2 ? 1 : 0))") try: first = next( i for i in reversed(synstackids) if i in texIgnoreMathZoneIds or i in texMathZoneIds ) return first != ignore except StopIteration: return False endglobal
これで、数学コンテキストでのみ適用するスニペットに
context "math()"
を追加できます。
context "math()" snippet sr "^2" iA ^2 endsnippet
数学的文脈は微妙なものであることに注意してください。 式モードでは、
\text{...}
を使用してテキストを書き込むこともあります。 この場合、スニペットは使用しません。 ただし、次の場合:
\[ \text{$...$} \]
、それらを適用する
必要が
あります。 これが、
math
コンテキストのコードがそれほど単純ではない理由です。 次のアニメーションは、これらの微妙な点を示しています。
その場でスペル修正
数式は要約の重要な部分ですが、私はほとんどの場合英語で印刷します。 1分あたり約80ワード、タイピングスキルはかなり優れていますが、多くのタイプミスを犯します。 それが、作業を妨げることなくスペルミスを修正するVimにバインディングを追加した理由です。 入力中に
Ctrl+L
を
Ctrl+L
と、前のスペルミスが修正されます。 次のようになります。
スペルチェックの私の設定:
setlocal spell set spelllang=nl,en_gb inoremap <Cl> <cg>u<Esc>[s1z=`]a<cg>u
ここでは、前のスペルエラー
[s
に移動し、最初のオプション
1z=
を選択して
`]a
を返します。 中央の
<cg>u
コマンドを使用すると、修正をすばやく元に戻すことができます。
結論として
Vimスニペットのおかげで、LaTeXコードを書くのはもう面倒ではなく、むしろ面白くなります。 オンザフライでのスペルと組み合わせることで、数学の講義を便利かつ迅速に概説することができます。
次の記事では、イラストをデジタルで描画してLaTeXドキュメントに埋め込むなど、他のトピックについて説明します。