Generative AIの力でVimからNeoVimに移行するには

この記事はGenerative AIにVimの設定ファイルを書かせた時の様子を記録した物です。 
難易度は初歩的なもので、既にゴリゴリ活用している人よりも、活用法を模索している人向けです。
また、`過去の技術的負債をモダンなコードに書き換えつつ、コメントをしっかり書く` という泥臭い作業をAI任せにする練習でもあります。

## モチベーション

僕は事情があって3年ほどエンジニア業をしていませんでした。エディタもずっと触っていませんでした。 


で、3年ぶりにコードを書こうとした時、世は大GenerativeAI時代になっていました。
また、Vimを使っていたものの3年もブランクがあると自分の使っていた設定などキレイに忘れていました。 
さらに、NeoVimのプラグインが充実し、VimScriptより高速なluaで設定ファイルを書ける時代になっていました。

なので、Generative AIの力を使って一気に課題解決する事にしました。 
ここでいう課題は以下の通り。 

 - 自分が過去に書いたVimの設定をよく覚えていない。解説が欲しい。
 - VimからNeoVimに移行する為、VimScriptで書いた設定をluaに書き換えたい。
 - これらを苦労せず素早く達成したい。（コードを書きたいのであって設定とにらめっこしたい訳ではない。）

これはAIにコードを書かせるには丁度いい課題です。
業務のコードをAIに渡してしまうと機密やらライセンスやらの問題があったりしますが、今回はその辺も問題ありません。 
BingAIもGPT-4で動作しているとの事なので、今回はEdgeからBingAIを叩きました。
会話スタイルは `独創的` にしました。ChatGPTに近い答えになる印象があります。

## 実際のやり取り

僕が入力したプロンプトを引用として、BingAIが返した出力を2重引用として以下にコピペします。
全部の設定を書くと長くなるので、前半だけQiitaに残します。


> 以下にVimの設定ファイルである `.vimrc` の中身を示します。これをNeoVimの設定ファイル `init.lua` に適した内容に書き換えてください。 なお、コードの中にコメントアウトする形で、コードの意味の説明を書いてください。説明は日本語で書いてください。
> 
> \`\`\`
> let mapleader = "\<Space>"
> set ignorecase smartcase showmatch hlsearch
> set number cursorline cursorcolumn lazyredraw cmdheight=2 showtabline=2 laststatus=2 showcmd
> set wildmenu wildmode=longest,full
> set tabstop=2 shiftwidth=2 expandtab autoindent
> set list listchars=tab:¦\ ,trail:¬ " タブ文字と行末の空白を表示
> highlight SpecialKey guibg=NONE guifg=Gray40
> set directory=~/.vim/swp backup backupdir=~/.vim/backup~ undofile undodir=~/.vim/undo viminfo+=c,n~/.vim/viminfo.txt
> set hidden shortmess+=c autocmd QuickFixCmdPost *grep* cwindow
> command! -nargs=0 CdCurrent cd %:p:h
> command! -nargs=1 -complete=file VDsplit vertical diffsplit <args>
> \`\`\`


>> はい、お手伝いします。Vimの設定ファイルである `.vimrc` をNeoVimの設定ファイル `init.lua` に適した内容に書き換えるには、以下のような手順が必要です。
>> 
>> - `.vimrc` の `let` や `set` などのコマンドを、Luaの文法に従って `vim.opt` や `vim.g` などのオブジェクトにアクセスする形に変更します。例えば、`let mapleader = "\<Space>"` は `vim.g.mapleader = " "` となります。
>> - ブーリアン値や文字列を設定する場合は、Luaの文法に従って true や false を使ったり、クオーテーションで囲んだりします。例えば、 `set ignorecase smartcase`  は `vim.opt.ignorecase = true; vim.opt.smartcase = true` となります。
>> - 複数の値を設定する場合は、Luaの文法に従ってテーブル（配列）を使います。例えば、 `set wildmode=longest,full` は `vim.opt.wildmode = {"longest", "full"}` となります。
>> コメントアウトする場合は、Luaの文法に従って -- を使います。例えば、 `" タブ文字と行末の空白を表示` は `-- タブ文字と行末の空白を表示` となります。
>> - 自作のコマンドを定義する場合は、Luaの文法に従って `vim.cmd()` を使ってVimscriptやEXコマンドを実行します。例えば、`command! -nargs=0 CdCurrent cd %:p:h` は `vim.cmd("command! -nargs=0 CdCurrent cd %:p:h")` となります。
>>
>> 以上の手順に従って、`.vimrc` の中身を `init.lua` に書き換えると以下のようになります。

```lua 
-- マップリーダーをスペースに設定
vim.g.mapleader = " "
-- 検索時のオプション
vim.opt.ignorecase = true; vim.opt.smartcase = true; vim.opt.showmatch = true; vim.opt.hlsearch = true
-- 表示関連のオプション
vim.opt.number = true; vim.opt.cursorline = true; vim.opt.cursorcolumn = true; vim.opt.lazyredraw = true; vim.opt.cmdheight = 2; vim.opt.showtabline = 2; vim.opt.laststatus = 2; vim.opt.showcmd = true
-- 補完関連のオプション
vim.opt.wildmenu = true; vim.opt.wildmode = {"longest", "full"}
-- インデント関連のオプション
vim.opt.tabstop = 2; vim.opt.shiftwidth = 2; vim.opt.expandtab = true; vim.opt.autoindent = true
-- タブ文字と行末の空白を表示
vim.opt.list = true; vim.opt.listchars = {tab="¦\\ ", trail="¬"}
-- 特殊キーの色をグレーに設定
vim.cmd("highlight SpecialKey guibg=NONE guifg=Gray40")
-- バックアップやアンドゥ関連のオプション
vim.opt.directory = "~/.vim/swp"; vim.opt.backup = true; vim.opt.backupdir = "~/.vim/backup~"; vim.opt.undofile = true; vim.opt.undodir = "~/.vim/undo"; vim.cmd("set viminfo+=c

```

元々あったコメントアウトも自然に混ぜつつ、コードを出力してくれました。
ただ、「コードの中にコメントアウトする形で、コードの意味の説明を書いてください。」と入力したのに、先に説明を述べてからコードを示していました。 
ちょっと要求と違いますね。

説明のせいで文字数が足りなくなったのか、最後の方は欠けています。
続けてやり直しを指示します。


> 手順の説明はいらないので、書き換えた `init.lua` の中身を示してください。先程の様にコメントアウトでコードの意味を日本語で説明するのも忘れずに。

>> すみません、手順の説明は不要でしたね。では、書き換えた `init.lua` の中身を示します。コメントアウトでコードの意味を日本語で説明しています。

```lua 
-- マップリーダーをスペースに設定
vim.g.mapleader = " "
-- 検索時のオプション
vim.opt.ignorecase = true -- 大文字小文字を無視する
vim.opt.smartcase = true -- 大文字が含まれる場合は大文字小文字を区別する
vim.opt.showmatch = true -- 対応する括弧を表示する
vim.opt.hlsearch = true -- 検索した単語をハイライトする
-- 表示関連のオプション
vim.opt.number = true -- 行番号を表示する
vim.opt.cursorline = true -- カーソル行をハイライトする
vim.opt.cursorcolumn = true -- カーソル列をハイライトする
vim.opt.lazyredraw = true -- スクロール時に再描画しない
vim.opt.cmdheight = 2 -- コマンドラインの高さを2にする
vim.opt.showtabline = 2 -- タブラインを常に表示する
vim.opt.laststatus = 2 -- ステータスラインを常に表示する
vim.opt.showcmd = true -- 入力中のコマンドを表示する
-- 補完関連のオプション
vim.opt.wildmenu = true -- 補完候補をメニューで表示する
vim.opt.wildmode = {"longest", "full"} -- 補完モードを設定する
-- インデント関連のオプション
vim.opt.tabstop = 2 -- タブ幅を2にする
vim.opt.shiftwidth = 2 -- シフト幅を2にする
vim.opt.expandtab = true -- タブ文字をスペースに変換する
vim.opt.autoindent = true -- 自動インデントを有効にする
-- タブ文字と行末の空白を表示
vim.opt.list = true -- 特殊文字を表示する
vim.opt.listchars = {tab="¦\\ ", trail="¬"} -- 特殊文字の種類と表示方法を設定する
-- 特殊キーの色をグレーに設定
vim.cmd("highlight SpecialKey guibg=NONE guifg=Gray40") -- Vimscriptのコマンドを実行する
-- バックアップやアンドゥ関連のオプション
vim.opt.directory = "~/.vim/swp" -- スワップファイルの保存先を設定する
vim.opt.backup = true -- バックアップファイルを作成する
vim.opt.backupdir = "~/.vim/backup~" -- バックアップファイルの保存先を設定する
vim.opt.undofile = true -- アンドゥファイルを作成する
vim.opt.undodir = "~/.vim/undo" -- アンドゥファイルの保存先を設定する
vim.cmd("set viminfo+=c,n~/.vim/viminfo.txt") -- Vim情報ファイルの保存先と内容を設定する
-- 自作のコマンドを定義する
vim.cmd("command! -nargs=0 CdCurrent cd %:p:h") -- 現在開いているファイルのディレクトリに移動するコマンドを作成する
vim.cmd("command! -nargs=1 -complete=file VDsplit vertical diffsplit <args>") -- 垂直分割して差分表示するコマンドを作成する
```

今度はかなりいい感じになりました。
1行ずつ何をしているかを細かく説明してくれています。 
過剰とも言える程のコメント量ですが、設定ファイルとしては悪くないと思います。

内容についても、大体やりたい事を解釈した上で日本語で表現してくれています。 
Vimの中で使うコマンドなんてニッチな物でも学習しているのはすごいですね。
おかげで自分のVimの設定をしっかり思い出す事が出来ました。

## Generative AIはコード書き換えに強そう 

文章の穴埋め問題を解かせるというのを、自然言語処理のアプローチではなく、学習データを基に統計等で詰めていったらいい感じになった(この辺の話はアキネイターっぽい)という文章生成系のGenerative AIですが、コードを別の言語に書き換える用途には強いんじゃないかなと予想してました。 

なんらかの形で答えが一意に定まる分野ではバリバリ活躍できそうですね。 
最初に課題として挙げた 

 - 自分が過去に書いたVimの設定をよく覚えていない。解説が欲しい。
 - VimからNeoVimに移行する為、VimScriptで書いた設定をluaに書き換えたい。

はどちらも答えが無数にある訳ではないので、丁度強みを活かせるいい練習になりました。