Vimにもノッチがほしい

この記事は DeNA 21新卒×22新卒内定者 Advent Calendar 2021 の 6 日目の記事です.
https://qiita.com/advent-calendar/2021/dena-21x22

# はじめに
今年の 10 月, M1 Max を搭載した MacBook Pro が発表されましたね.
https://www.apple.com/jp/newsroom/2021/10/apple-unveils-game-changing-macbook-pro/

端子がかなり増えたことや処理速度に驚いた人も多いのではないでしょうか？

私もかなり驚きました.
しかし, それ以上に驚いたことがあります.
それがノッチの登場です.
FaceID 用のカメラを搭載する上で必要ではありますが, まさかノッチにするとはという感情でした.

従来の MacBook にノッチをつけるソフトウェアを作っている方もいました.
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/Y7S9xrZiHm">https://t.co/Y7S9xrZiHm</a> <a href="https://t.co/XMqjD8z6AB">pic.twitter.com/XMqjD8z6AB</a></p>&mdash; Chris Jones (@cmsj) <a href="https://twitter.com/cmsj/status/1450396500610138114?ref_src=twsrc%5Etfw">October 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

私もかなりの衝撃を受けたので普段使っているソフトウェアでノッチを表示したくなってしまいます.

そこで今回は私が普段使っているソフトウェアである Vim でノッチを表示したいと思います.

# Vim とは
モードという概念がある少し特殊なテキストエディタです.

- normal mode: 特殊なキーコンフィグを用いてテキストの編集を行う
- insert mode: テキストの記述を行う
- visual mode: テキストの範囲選択を行う
- command mode: コマンドを実行する

Vim ではこれらのモードを駆使してテキストの記述, 修正を行っていきます.

また, Vim script という Vim の設定を書く専用の script 言語も存在しており, ユーザーが簡単に機能を拡張できるのも特徴です.

vim-jp というコミュニティもあり, 今でもたくさんの人に愛されているテキストエディタです.

# 表示位置のイメージ
私が使っている Vim は普段以下のようになっています.
![Screenshot from 2021-12-01 16-36-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/3779c59d-349f-c1fd-cc71-55b4f76420e1.png)

MacBook Pro や iPhone のノッチが画面上部中央にあるので以下の画像のように作っていきたいと思います.
![aaaaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/95212dcb-69d2-0fb4-24a3-db09f8814097.png)

# ノッチのような四角形の表示
次にノッチのような四角形を表示します.
Vim には popup window という機能があり, 表示しているテキストの上に window を表示することができます.
※Neovim にも同じような機能として floating window があります
今回は popup window を使い, ノッチ独特の切れ込みを再現していきたいと思います.

以下は text という変数に収められた値を popup window 上に表示するソースコードです.

```vim
let text = 'hogehoge'

call popup_create(text, {})
```

こちらを以下のどちらかで読み込むことで画面中央に hogehoge というテキストが popup window で表示されます.

- vimrc に記述する
- ソースコードを記述したファイルを `source hoge.vim` で読み込む

![Screenshot from 2021-12-01 18-02-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/dbb01240-28fd-b9cb-dbcd-3f6b7d876120.png)

これでベースとなる popup window の表示が完了しました.

# 位置の調整
次に位置の調整を行っていきます.
デフォルトだと Vim のど真ん中に表示されるため, これをノッチの位置(中央上部)に移動させます.

Vim の popup windowを作る関数 `popup_create()` は第二引数に辞書型を受け取ります.

そこで位置の調整や popup window のタイトル, ハイライトなどが指定できます.

ひとまず位置の調整のみ行ってみましょう.
上記の popup window を表示するコードを以下のように修正します.

```vim
let text = 'hogehoge'

call popup_create(text, {'line': 1})
```

すると以下のように hogehoge という文字列が中央上部に表示されます.
![Screenshot from 2021-12-01 22-29-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/626bfca3-8c95-401b-238b-1af5c3c92963.png)

# 表示内容をいじっていく
MacBook Pro のノッチには hogehoge なんて表示されていません.
あるのはカメラとカメラが起動していることを示すLEDです.
また，画像を見る限りこんなに小さくありません.
それらを再現していきましょう.

## 表示列の調整
`popup_create()` は文字列や数値以外にも配列を受け取ってくれます.
画像を見る限り, 3 行分くらいはありそうなので, 以下のような配列を受け取ってもらいましょう

```vim
let content = ['', '', '']
```

![Screenshot from 2021-12-01 22-39-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/43d1cb23-467f-9f17-4450-8d082b19eb6a.png)


薄くて分かりづらいですが中央上部に 3 行に渡って表示されています.

## カメラの再現
次にカメラの再現です.

2 行目にカメラの穴を模した `⚫` を表示します.
ここでも変更するのは `popup_create()` に渡す変数の部分です.

```vim
let content = ['', '              ⚫              ', '']
```

popup window はオプションで指定しない限り幅が渡した要素の中で最も長いものに統一されます.
そのため, 2 行目のみの編集で問題ありません.

![Screenshot from 2021-12-01 22-57-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/d64425d8-8695-86df-5570-38426aa5d155.png)

## カメラ使用時の LED を再現
MacBook ではカメラ使用時にカメラの横の LED が緑色に点灯するため再現します.

これも `popup_create()` に渡す変数をいじっていきます.
残念ながら緑の丸は絵文字になかったため, 青のまるで代用します.

```vim
let content = ['', '              ⚫   🔵          ', '']
```

![Screenshot from 2021-12-01 22-56-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231013/33f537ce-339f-acbb-56b2-d8709ca103e5.png)

# LED オンオフの再現
現状では常にカメラ使用状態です.
これではノッチとは言えないでしょう.

そこで先程紹介したモードの概念を活用し, 

- normal mode 時はカメラを使っていない 
- insert mode 時はカメラを使っている 

として LED のオンオフを再現しましょう.

Vim には指定したイベントが発火したときに関数などを実行する機能 `autocmd` があるためそれを使用します.

`autocmd` には

- カラースキームを読み込んだあと
- ファイルを読み込んだあと
- テキストが編集されたあと

など様々なイベントが用意されていますが今回は

- insert mode に入ったあと `InsertEnter`
- insert mode を出たあと `InsertLeave`

の 2 つを使います.

まずはカメラ ON/OFF それぞれのノッチを表示する関数を作りましょう

```vim
func! s:popupCameraON() abort
    call popup_close(g:notchWinID)

    let content = ['', '              ⚫   🔵          ', '']
    let g:notchWinID = popup_create(content, {'line': 1})
endfunc

func! s:popupCameraOFF() abort
    call popup_close(g:notchWinID)

    let content = ['', '              ⚫              ', '']
    let g:notchWinID = popup_create(content, {'line': 1})
endfunc

call s:popupCameraOFF()
```

ここで初めて `popup_close()` という関数が出てきましたが, これは指定した ID の popup window を閉じる関数です.
popup window の ID は `popup_create()` の返り値で受け取れます.

次にこの用意した関数をそれぞれイベントで実行されるようにします.
先程の関数の下に以下のコードを記述してください.

```vim
augroup VimNotch
    autocmd!
    autocmd InsertEnter * call s:popupCameraON()
    autocmd InsertLeave * call s:popupCameraOFF()
augroup END
```

すると以下のようにモードが切り替わったタイミングでノッチも切り替わります！
少し分かりづらいですが, 左下に INSERT と表示されているときが insert mode, NORMAL と表示されているときが normal mode です.
<iframe width="560" height="315" src="https://www.youtube.com/embed/7voDQnMdItE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 最後に
かなり雑ですが Vim にもノッチをつけることができました.

これで M1 Max MacBook Pro や プライベート用の MacBook を買うお金のない人でもノッチ生活を楽しむことができそうです.