【環境構築】NeoVim

# 導入経緯

最近競技プログラミングのためにviコマンドを使えるようになりたいと考え, NeoVimを導入しました.
VSCodeの拡張機能でも良いのですが, せっかくなのでよりカスタマイズ性の高いNeoVimの環境構築を行いました.
まだまだ機能は不十分ですが, ゆくゆくは自分好みの便利なエディタに育てていく予定です.
特に詳しいわけではありませんが, 導入手順をまとめました.
ご指摘やお勧めのプラグイン等ありましたら, コメントをお願いいたします.

![neovim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762056/ac191f28-5c74-fe24-7e58-61d6d48910ea.png)

# 目次

- [動作環境](#動作環境)
- [導入手順](#導入手順)
  - [1. Homebrewのインストール](#1-homebrewのインストール)
  - [2. NeoVimのインストール](#2-neovimのインストール)
  - [3. NeoVimプラグインのインストール](#3-neovimプラグインのインストール)
    - [3-1. プラグインマネージャのインストール](#3-1-プラグインマネージャのインストール)
    - [3-2. プラグインのインストール](#3-2-プラグインのインストール)
    - [3-3. お勧めのプラグイン](#3-3-お勧めのプラグイン)
  - [A. 基本的なviコマンド](#a-基本的なviコマンド)
- 脚注

# 動作環境

私がNeoVimを導入した際の環境です。
以下記事では基本的にmacOSでの環境構築について解説していきます.

|  |  |
| --- | --- |
| チップ | Apple M3 |
| OS | macOS Sonoma 14.4.1 |
| シェル | zsh |
| ターミナル | iTerm2 |

:::note warn
ターミナルは標準のものではなく, iTermなどの使用をお勧めします.
標準のターミナルでは, 特にカラースキーマなどのプラグインが機能しない可能性があります.
:::

# 導入手順

## 1. Homebrewのインストール

まずはNeoVimをインストールするために, パッケージマネージャをインストールします.
macOSやLinuxなどのUnix系のシステムでは, 一般にHomebrewを使用します.

既にインストールされているかを確認するため, ターミナルに以下のコマンドを入力してください.

```zsh:Terminal
brew --version
```
<br>

- **インストールされている場合**

    以下のようにバージョン情報が表示されます.
    
    ```zsh:Terminal
    Homebrew 3.X.X
    ```

    以下のコマンドを実行してHomebrewを最新の状態にしてください.

    ```zsh:Terminal
    brew update
    ```
    <br>

- **インストールされていない場合**
    `brew`コマンドが見つからない旨のエラーが出力されます.
    ```zsh:Terminal
    brew: command not found
    ```

    エラーが出力された場合は, 以下のコマンドを実行し, インストールしてください.
    
    ```zsh:Terminal
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    ```

## 2. NeoVimのインストール

続いてNeoVimをインストールします.
ターミナルに以下のコマンドを入力してください.

```zsh:Terminal
brew install neovim
```

インストール完了後, ターミナルに

```zsh:Terminal
nvim
```

と入力すると, 正常にインストールされていればNeoVimの起動画面が表示されると思います.

毎回`nvim`と入力するのは面倒なので, エイリアスを設定します.
ターミナルで.bashrcや.zshrcを編集し, 以下の一文を追加してください.

```zsh:.zshrc
alias v='nvim'
```

これで, `v`と入力するだけでNeoVimを起動することができます.

## 3. NeoVimプラグインのインストール

続いてNeoVimの便利なプラグイン群をインストールしていきます.

初めに, NeoVimの設定に関するディレクトリ構造をお見せします.
これに基づき, 以下で設定を記述していきます.

:::note warn
以下のディレクトリ構造は一例です, 慣れてきたら自分でカスタマイズしましょう.
:::

```
.config
    └─ nvim
      ├─ init.lua
      └─ lua
         ├─ plugin_manager.lua
         └─ plugins
            ├─ tokyonight.lua
            ⋮
```

- `init.lua`:
  NeoVimの基本設定を記述するためのluaファイル.
  起動時に一番初めに読み込まれる.
  ここに参照関係を規定し, プラグイン毎の設定を別ファイルに分ける.
  &rarr; 設定ファイルが長大にならないようにする.

- `lua`:
  このディレクトリに保存したluaファイルを, `init.lua`から呼び出す.

- `plugins`:
  プラグイン毎の個別の設定を保存するディレクトリ.

### 3-1. プラグインマネージャのインストール

初めに, プラグインマネージャをインストールします.
選択肢は多いですが, 個人的には **Lazy.nvim** がお勧めです（2024/06現在）.

:::note info
以下では, Lazy.nvimを前提に環境構築を行います.
:::

`init.lua`を作成し, 以下を追記します.

```zsh:Terminal
# NeoVimの設定ディレクトリに移動
cd .config/nvim

# 設定ファイルを作成し, NeoVimで開く
v init.lua
```

:::note warn
viコマンドでの操作に慣れていない場合,
[4. 基本的なviコマンド](#4-基本的なviコマンド)を参考にしてください.
:::

```lua:init.lua
require('plugin_manager')
```

この記述により, `lua/plugin_manager.lua`が読み込まれます.

`lua/plugin_manager.lua`に`Lazy.nvim`をインストールするための記述を追加していきます.

```zsh:Terminal
# luaディレクトリに移動
cd lua

# 設定ファイルを作成し, NeoVimで開く
v plugin_manager.lua
```

```plugin_manager.lua
-- Neovimのデータディレクトリのパスに "lazy/lazy.nvim" を追加, プラグインの保存パスを設定
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"

-- 指定されたパスにプラグインが存在しない場合, Gitを使ってプラグインをクローン
if not (vim.uv or vim.loop).fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "https://github.com/folke/lazy.nvim.git",
        "--branch=stable",
        lazypath,
    })
end

-- ランタイムパスの先頭にプラグインのパスを追加
vim.opt.rtp:prepend(lazypath)
```

NeoVimを再起動し, コマンドモードで`:Lazy`と入力すると, `Lazy.nvim`が起動します.

以上でプラグインマネージャのインストールは完了です.

### 3-2. プラグインのインストール

以下では, 私が個人的にお勧めするプラグインとその導入方法について解説していきます.

#### 基本的な導入の流れ

```
.config
    └─ nvim
      ├─ init.lua
      └─ lua
         ├─ plugin_manager.lua
         ├─ plugins.lua
         └─ plugins
            ├─ tokyonight.lua
            ⋮
```

- `init.lua` &larr; `plugins.lua`:
  `plugins.lua`にプラグインをインストールするための記述をし, `init.lua`で読み込む.
- `init.lua` &larr; `plugins\XXXXX.lua`:
  個別のプラグイン設定を`init.lua`から読み込む.

文字ベースで解説してもわかりづらいかと思いますので, 以下で実際に設定していきましょう.

#### テーマの変更

- **`folke/tokyonight`**

https://github.com/folke/tokyonight.nvim

背景やコードに色を付けてくれる, いわゆるカラースキーマの一種です.
試しにこちらを導入していきます.
  
まずは, プラグインマネージャにTokyoNightをインストールさせます.

```zsh:Terminal
# luaディレクトリに移動
cd lua

# NeoVimで開く
v plugins.lua
```

```lua:plugins.lua
require('lazy').setup({
  -- tokyonight
  "folke/tokyonight.nvim",
})
```

続いて`plugins.lua`を`init.lua`に認識させます. 以下を追記してください.
  
```zsh:Terminal
# NeoVimで開く
v init.lua
```

```lua:init.lua
require('plugins')
```
  

これで, NeoVim起動時に`Lazy.nvim`が`TokyoNight`を自動的にインストールしてくれます.
  
このままでもテーマは適用されるのですが, デフォルトでは少々味気ないため,
見た目をさらにカスタマイズしていきます.

```zsh:Terminal
# pluginsディレクトリに移動
cd lua/plugins

# 設定ファイルを作成し, NeoVimで開く
v tokyonight.lua
```

```tokyonight.lua
require("tokyonight").setup({
  style = "night",
  transparent = true,
  styles = {
    comments = { italic = true },
    keywords = { italic = true }
  }
})

-- 背景色を透過
vim.cmd('colorscheme tokyonight')
vim.cmd('highlight Normal guibg=NONE ctermbg=NONE')
```

続いてこの設定ファイルを`init.lua`に読み込ませます. 以下を追記してください.

```zsh:Terminal
# NeoVimで開く
v init.lua
```

```init.lua
require('plugins/tokyonight')
```

これでテーマの設定が完了しました.

NeoVimを再起動してみてください.
TokyoNightが適用され, 背景色や文字色が変更されているはずです.

### 3-3. お勧めのプラグイン

基本的に上述の例と同様, 下記手順にて導入することができます.

1. `plugins.lua`にインストールしたいプラグイン情報を追記
2. `plugins`ディレクトリ内にプラグイン毎の設定ファイルを作成, 記述
3. `init.lua`に2.で作ったファイルを読み込む設定を追加

:::note info
以下はその他お勧めのプラグインです.
個別の設定等は各リポジトリのREADMEを参照してください.
:::

- **`nvim-tree/nvim-tree`**
  ディレクトリ構造のツリーをNeoVim内に表示します.

https://github.com/nvim-tree/nvim-tree.lua

- **`nvim-tree/nvim-web-devicons`**
  ファイルの拡張子毎に対応するカラーアイコンを提供します.
  nvim-treeと組み合わせて使います.

  デフォルトのフォントでは機能しないため, READMEを参考にNerd Fontをターミナルに設定してください.

https://github.com/nvim-tree/nvim-web-devicons

- **`nvim-treesitter/nvim-treesitter`**
  コードの構文を解析し, 自動で色をつけてくれます.

https://github.com/nvim-treesitter/nvim-treesitter

- **`nvim-lualine/lualine.nvim`**
  エディタ下部にステータスバーを表示します.

https://github.com/nvim-lualine/lualine.nvim

- **`yamatsum/nvim-cursorline`**
  カーソルのある行をハイライトします.

https://github.com/yamatsum/nvim-cursorline

- **`akinsho/toggleterm.nvim`**
  NeoVim上でターミナルを使えるようにします.

https://github.com/akinsho/toggleterm.nvim

:::note info
参考までに, 私が使っている設定を以下にまとめておきます.
まだまだ機能が不足しているため, 今後も追記, メンテナンス予定です.

プラグイン毎の設定ファイルに関しては, ほぼデフォルトのため割愛します.
:::

<details><summary>ディレクトリ構造</summary>

```
.config
    └─ nvim
      ├─ init.lua
      ├─ plugins.lua
      └─ lua
         ├─ plugin_manager.lua
         └─ plugins
            ├─ tokyonight.lua
            ⋮
```
</details>

<details><summary>設定ファイル群</summary>

```lua:.config\nvim\init.lua
-- General settings
local opt = vim.opt

-- Set width for 2-byte characters to double
opt.ambiwidth = 'double'

-- Enable automatic indentation
opt.autoindent = true
-- Enable smart indentation
opt.smartindent = true

-- Set the number of spaces that a <Tab> in the file counts for
opt.tabstop = 4
-- Set the number of spaces that a <Tab> counts for while performing editing operations
opt.softtabstop = 4
-- Set the number of spaces to use for each step of (auto)indent
opt.shiftwidth = 4

-- Show line numbers
opt.number = true

-- Enable 24-bit RGB color in the TUI
opt.termguicolors = true

-- Load the package manager
require('plugin_manager')

-- Load plugin definitions
require('plugins')

-- Apply plugin settings
require('plugins/tokyonight')
require('plugins/nvim-web-devicons')
require('plugins/nvim-tree')
require('plugins/lualine')
require('plugins/nvim-cursorline')
require('plugins/toggleterm')
require('plugins/nvim-treesitter')
```

```lua:.config\nvim\plugins.lua
-- General settings for Lazy
require('lazy').setup({
    -- tokyonight
    "folke/tokyonight.nvim",

    -- nvim-web-devicons
    'nvim-tree/nvim-web-devicons',

    -- nvim-tree
    {
        'nvim-tree/nvim-tree.lua',
        dependencies = {'nvim-tree/nvim-web-devicons'}
    },

    -- treesitter
    {
        'nvim-treesitter/nvim-treesitter',
        run = ':TSUpdate'
    },

    -- lualine
    {
        'nvim-lualine/lualine.nvim',
        dependencies = {'nvim-tree/nvim-web-devicons'}
    },

    -- nvim-cursorline
    'yamatsum/nvim-cursorline',lt configuration
    },
    
    -- toggleterm
    {
        'akinsho/toggleterm.nvim',  -- Terminal integration for Neovim
        version = "*",  -- Use the latest version
        config = true  -- Enable default configuration
    }
})

```

```lua:.config\nvim\plugin_manager.lua
-- Set the path for the plugin by appending "lazy/lazy.nvim" to Neovim's data directory path
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"

-- If the plugin does not exist at the specified path, clone it using Git
if not (vim.uv or vim.loop).fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "https://github.com/folke/lazy.nvim.git",
        "--branch=stable",
        lazypath,
    })
end

-- Add the plugin path to the beginning of the runtime path
vim.opt.rtp:prepend(lazypath)
```
</details>

## A. 基本的なviコマンド

補足ですが, 以下は私がよく使う基本的なviコマンドです.

ファイルを編集する際に参考にしていただければと思います[^1].

### A-1. 移動系コマンド

| モード | コマンド | 動作 |
|  --- | --- | --- |
| NORMAL | `h` | **左**に移動 |
| NORMAL | `j` | **下行先頭文字**に移動 |
| NORMAL | `k` | **上**に移動 |
| NORMAL | `l` | **右**に移動 |
| NORMAL | `w` | **ワード区切りで右**に移動 |
| NORMAL | `b` | **ワード区切りで左**に移動 |
| NORMAL | `W` | **スペース区切りで右**に移動 |
| NORMAL | `B` | **スペース区切りで左**に移動 |
| NORMAL | `e` | **現ワードの最後の文字**に移動 |
| NORMAL | `H` | **画面内の先頭行**に移動 |
| NORMAL | `M` | **画面内の中央行**に移動 |
| NORMAL | `L` | **画面内の最終行**に移動 |
| NORMAL | `G` | **ファイルの最終行**に移動 |
| NORMAL | `1G` | **ファイルの1行目**に移動 |
| NORMAL | `10G` | **ファイルの10行目**に移動 |
| NORMAL | `Command` + `f` | **一画面先**に移動 |
| NORMAL | `Command` + `d` | **半画面先**に移動 |
| NORMAL | `Command` + `b` | **一画面前**に移動 |
| NORMAL | `Command` + `u` | **半画面前**に移動 |

### A-2. モード切替コマンド（NORMAL &rarr; INSERT）

| モード | コマンド | 動作 |
|  --- | --- | --- |
| NORMAL | `a` | **カーソルの右**に挿入 |
| NORMAL | `A` | **カーソルのある行末**に挿入 |
| NORMAL | `i` | **カーソルの左**に挿入 |
| NORMAL | `I` | **カーソルのある行頭**に挿入 |
| NORMAL | `o` | **カーソルの下行**に挿入 |
| NORMAL | `O` | **カーソルのある上行**に挿入 |

### A-3. モード切替コマンド（INSERT &rarr; NORMAL）

| モード | コマンド | 動作 |
|  --- | --- | --- |
| INSERT | `Esc` | **NORMAL**モードに切替 |

### A-4. テキストの削除コマンド

| モード | コマンド | 動作 |
|  --- | --- | --- |
| NORMAL | `x` | **カーソルの文字**を削除 |
| NORMAL | `X` | **カーソルの左の文字**を削除 |
| NORMAL | `dw` | **ワード**を削除 |
| NORMAL | `dd` | **行**を削除 |
| NORMAL | `dG` | **カーソルがある行からファイルの最終行まで**を削除  |
| NORMAL | `d1G` | **カーソルがある行ファイルの先頭行からまで**を削除  |
| NORMAL | `:X,Yd` | **X行目からY行目まで**を削除 |

### A-5. テキストのコピーコマンド

| モード | コマンド | 動作 |
|  --- | --- | --- |
| NORMAL | `yy` or `Y` | **行**をコピー |
| NORMAL | `p` | コピーを**下行**に挿入 |
| NORMAL | `P` | コピーを**上行**に挿入 |

### A-6. 保存と終了

| モード | コマンド | 動作 |
|  --- | --- | --- |
| NORMAL | `:w` + `Return` | **保存** |
| NORMAL | `:q` + `Return` | **終了** |
| NORMAL | `:wq` + `Return` | **保存して終了** |
| NORMAL | `:q!` + `Return` | **保存しないで終了** |

[^1]: [vi の基本コマンドの一覧](https://docs.oracle.com/cd/E19253-01/816-3946/editorvi-tbl-83/index.html)