Vim(Neovim)だけでAtCoderに参加したい

## できたもの
[ka-tsu-mo/at-vim-coder](https://github.com/ka-tsu-mo/at-vim-coder)

![atvimcoder_demo](https://user-images.githubusercontent.com/46083154/153001913-451fc402-c39b-4e38-8186-5627959f99c5.gif)

最近AtCoderに参加し始めましたが、もっと過去問をといて本番でいいパフォーマンスを出せるように練習が必要だなと感じております。
ブラウザを開かずに使い慣れたVimのキーバインドだけで完結できるようなプラグインを目指しました。といってもやっていることはスクレイピングだけですが...

## 工夫したところ
AtCoderは問題文に数式が用いられていることがあります。このプラグインではなるべく見やすいように整えました。
`\frac`をスラッシュで置き換えるコードを紹介します。
下記関数に`re.compile(r'\\frac\{.+\}')`によって生成される[正規表現オブジェクト](https://docs.python.org/ja/3/library/re.html#re-objects)の`search`でマッチした[マッチオブジェクト](https://docs.python.org/ja/3/library/re.html#match-objects)を渡します。
Listのapendとpopのみを用いることでスタックのように振る舞います。

```py
def _frac_to_slash(self, matchobj):
	text = matchobj.group(0)
	table = str.maketrans('{}', '()')
	for i in range(2):
		stack = []
		for j in range(len(text)):
			if text[j] == '{' or text[j] == '}':
				stack.append(j)
			if text[j] == '}':
				if len(stack) == 2 and text[stack[0]] == '{' and text[stack[1]] == '}':
					break
				try:
					stack.pop()
					stack.pop()
				except:
					return matchobj.group(0)
			if i == 0:
				try:
					if len(text[stack[0]:stack[1]+1]) == 3:
						numerator = text[stack[0]+1]
					else:
						numerator = text[stack[0]:stack[1]+1].translate(table)
					text = text[stack[1]+1:]
				except:
					return matchobj.group(0)
			if i == 1:
				try:
					if len(text[stack[0]:stack[1]+1]) == 3:
						denominator = text[stack[0]+1]
					else:
						denominator = text[stack[0]:stack[1]+1].translate(table)
					return numerator + '/' + denominator + text[stack[1]+1:]
				except:
					return matchobj.group(0)
```

例として、動画にも写っている[ABC145のC問題](https://atcoder.jp/contests/abc145/tasks/abc145_c)に使われている`\frac`を引用して紹介します。

```tex
\frac{\left(1+\sqrt{2}\right)+\left(1+\sqrt{2}\right)+\left(2\right)+\left(1+\sqrt{2}\right)+\left(2\right)+\left(1+\sqrt{2}\right)}{6}
```
このように中かっこの中に中かっこがあるので、正規表現だけではどうにもなりません。
上記ソースコードでは`{`または`}`が出現したらそのインデックスをスタックにつみ、`}`が出現した場合、対となるかっこと共にスタックから取り出します。上記の例を可視化すると(横に積み重なっていくイメージ)

```
[]
[5]
[5, 19]
[5, 19, 21]
[5]
[5, 43]
[5, 43, 45]
[5]
[5, 82]
[5, 82, 84]
[5]
[5, 121]
[5, 121, 123]
[5]
[5, 131]
```
こんな感じで分子部分が取り出せるので、もう一度同じ動作をして分母を取り出しスラッシュでくっつけると...

```
((1+√(2))+(1+√(2))+(2)+(1+√(2))+(2)+(1+√(2)))/6
```

こうなります。

見づらい!

絶対もっといい実装あるだろと思いつつ、他に思いつかないし`\frac`よりいいと思うのでこのまま使っています。
これも競プロ力の足りなさなんですかね。

## まとめ
- VimだけでAtCoderの問題に挑戦できるプラグインを作った。
- pythonの単体テスト用のモジュール使えばよかった...。
- 過去問の事ばかり考えていて、本番のコンテストに参加登録するコマンドを入れ忘れた(そのうち実装するはず)。
    - 試したことがないからわからないが、参加登録ボタンを押さなかった場合もコンテストの時間に問題文見れるんだろうか。
- 過去問いっぱいといて強くなりたい。

## プラグインに関して
- 今のところ、C++とPython3とGoにしか対応してません。
    - [Language Test](https://language-test-201603.contest.atcoder.jp/)の表のコマンドを全部試すのはしんどかったので...
    - 使いたい言語があればContributeしていただければと思います。
    - [新しいページ](https://atcoder.jp/contests/language-test-202001)が更新されたらこちらも更新していこうかと思っています。
- 企業のコンテストは画像を使っている場合があるので、ブラウザで見た方がいいと思います。
- WindowsのNeovimではテストしてないので、動くかわかりません。

## 参考にしたサイト
- [Pythonでvim pluginを書く](https://qiita.com/zakuro9715/items/98449dd4c6b9e1d61ef5)
- [Vim一年生による、Vimプラグイン作成指南](https://qiita.com/aratana_tamutomo/items/4f754c301fb911ff54e8)
- [続・初めてのvimプラグイン作成 - 最小限なvimプラグイン](https://qiita.com/bonjin6770@github/items/31e60707ecf2ad6c4496)