【🔰初心者向け】Vimのススメ② [縦移動をマスターしよう！]

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。今回の記事はVimの続きです。連続記事ですので、前記事を読んでから読むことをオススメします。

前記事👇

https://qiita.com/ikemura-ren/items/9640f9394a6451ff91a9

![da60bb9b-3a26-49be-af58-1164f6c9293c_720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/4a217036-7f88-4d33-aec4-0301c597e077.png)


## ノーマルモードについて
ノーマルモードは、Vimで最も大事なモードだと思っています。ここをクリアしない限り、Vimを使いこなすことはできません。難易度が高い理由は、便利な機能を提供するキーが多すぎることです。

:::note info
まず、Vimでは十字キーを使わない美学があり、十字キーを使ったカーソル移動に慣れている人はここで詰まります。（十字キーが使えないわけではありません）
:::



## カーソルの移動について
#### 基本の
カーソルの移動は、まず`h`、 `j`、 `k`、 `l`で十字キーと同じ動きをします。
少々クセがあるので、最初はまずこれに慣れることが大事です。

##### `h`：左にカーソルを移動
##### `l`：右にカーソルを移動
##### `k`：上にカーソルを移動
##### `j`：下にカーソルを移動

:::note info
最初はこれだけを反復練習をするのがオススメです。
:::

#### 行頭と行末への移動
次に行頭と行末への移動を紹介します。
こちらは`0`で**行頭**に行きます。そして`$`で**行末**に行きます。これは若干押しにくいので、人によってはキーマップを変えている可能性が高いです。

:::note info
今回はキーバインド周りを説明する気はありません。
:::

##### `0`：行頭にカーソルを移動
##### `$`：行末にカーソルを移動


## ここで注意点
Vimは慣れると高速に移動できるエディタですが、移動に際して注意点があります。

### Vimは横の移動に強いが、縦の移動に弱い！

これから縦の移動の説明をしますが、キーマップはそれほど多くありません。
まずは縦の動きを学んで、その後に横移動をマスターしていきましょう。

:::note info
今回は、実際のコードを使って挙動を確かめていきます。
よかったら、以下のトグル内にあるコードをお使いください🖐️
:::


<details><summary>今回Vimで使うPythonのコード🐍</summary>

```python
from flask import Flask, render_template, request, redirect, url_for, jsonify

app = Flask(__name__)

# サンプルのTodoデータ
todos = [
    {'id': 1, 'task': 'Flaskの勉強', 'completed': False},
    {'id': 2, 'task': 'Dockerのセットアップ', 'completed': True},
    {'id': 3, 'task': 'コードレビュー', 'completed': False}
]

# ホームページ表示（Todo一覧）
@app.route('/')
def index():
    return render_template('index.html', todos=todos)

# 新しいTodoを追加
@app.route('/add', methods=['POST'])
def add_todo():
    task = request.form.get('task')
    if task:
        new_todo = {'id': len(todos) + 1, 'task': task, 'completed': False}
        todos.append(new_todo)
    return redirect(url_for('index'))

# Todoを削除
@app.route('/delete/<int:todo_id>', methods=['POST'])
def delete_todo(todo_id):
    global todos
    todos = [todo for todo in todos if todo['id'] != todo_id]
    return redirect(url_for('index'))

# Todoの完了状態を変更
@app.route('/toggle/<int:todo_id>', methods=['POST'])
def toggle_todo(todo_id):
    for todo in todos:
        if todo['id'] == todo_id:
            todo['completed'] = not todo['completed']
    return redirect(url_for('index'))

# JSON形式でTodoリストを返すAPI
@app.route('/api/todos', methods=['GET'])
def api_todos():
    return jsonify(todos)

# 特定のTodoをJSON形式で返すAPI
@app.route('/api/todos/<int:todo_id>', methods=['GET'])
def api_todo(todo_id):
    todo = next((t for t in todos if t['id'] == todo_id), None)
    if todo:
        return jsonify(todo)
    return jsonify({'error': 'Not found'}), 404

# JSON形式で新規Todo追加API
@app.route('/api/todos', methods=['POST'])
def api_add_todo():
    task = request.json.get('task')
    if task:
        new_todo = {'id': len(todos) + 1, 'task': task, 'completed': False}
        todos.append(new_todo)
        return jsonify(new_todo), 201
    return jsonify({'error': 'Task is required'}), 400

# JSON形式でTodo削除API
@app.route('/api/todos/<int:todo_id>', methods=['DELETE'])
def api_delete_todo(todo_id):
    global todos
    todo = next((t for t in todos if t['id'] == todo_id), None)
    if todo:
        todos = [t for t in todos if t['id'] != todo_id]
        return jsonify({'result': 'Deleted'}), 200
    return jsonify({'error': 'Not found'}), 404

# JSON形式でTodo完了状態変更API
@app.route('/api/todos/<int:todo_id>/toggle', methods=['PUT'])
def api_toggle_todo(todo_id):
    todo = next((t for t in todos if t['id'] == todo_id), None)
    if todo:
        todo['completed'] = not todo['completed']
        return jsonify(todo), 200
    return jsonify({'error': 'Not found'}), 404

if __name__ == '__main__':
    app.run(debug=True, port=5000)

```

:::note info
よかったら、実際の動作を確認するためにローカルでお使いください。
:::


</details>

## Vimの縦の動き
さて、では早速Vimで縦の動きを行うためのキーマップを見ていきましょう。
### ファイルの先頭行、最終行

##### `gg`：先頭行にカーソルを移動
##### `G`：最終行にカーソルを移動

![output1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/c1de30fb-b951-4355-911a-0ac1663e2d64.gif)

### 半画面分、上下に移動

##### `Ctrl + u`：半画面分『上』にカーソルを移動
##### `Ctrl + d`：半画面分『下』にカーソルを移動

![output2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/abf9b1ff-2868-4994-8ee7-88b13c366065.gif)


## 半画面分、上下に移動

##### `Ctrl + b`：1画面分『上』にカーソルを移動
##### `Ctrl + f`：1画面分『下』にカーソルを移動

:::note info
こちらは先ほどの半画面と同じような動きをします。ですので動画はありません。ローカルでお試しください。
:::

## 段落単位での移動

##### `{`：段落単位で『上』にカーソルを移動
##### `}`：段落単位で『下』にカーソルを移動

![output3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/240e4538-9994-4406-8056-ee5950ac4a59.gif)

:::note info
段落はコーディングしていると必ず発生しますので、この移動を知っていると便利だと思います。
:::


## 行を指定しての移動

##### `行番号 + G`：指定した行番号の行頭に移動
##### `:行番号 + Enter`：指定した行番号の行頭に移動

:::note info
こちらはどちらでも構いません。私はコマンドモードで`:行番号 + Enter`に慣れきっているのでそちらを使用しています。
:::
ちょっとわかりにくいですが👇
![output4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/893d7ac2-8627-40d2-8b7c-a89bd5dbe58f.gif)


## 指定した数字分、上下にカーソルを移動

##### `移動したい行数 + gk `：指定した行数分、『上』にカーソルを移動
##### `移動したい行数 + gj`：指定した行数分、『下』にカーソルを移動

##### `移動したい行数 + 『 - 』`：指定した行数分、『上』にカーソルを移動
##### `移動したい行数 + 『 + 』`：指定した行数分、『下』にカーソルを移動

##### `移動したい行数(-1) + 『 _ 』`：指定した行数-1行下の行頭にカーソルを移動
##### `移動したい行数(-1) + 『 $ 』`：指定した行数-1行下の行末にカーソルを移動

:::note warn
ここでご紹介した縦移動のキーマップは、最後から2番目以外、私はあまり使っていないです。なので、紹介くらいだと思ってもらって良いです。
:::


## おまけ
上下の移動ではないのですが、スクロールについても少しご紹介します。
| コマンド    | 説明                                                |
|-------------|-----------------------------------------------------|
| `zt`        | カーソル行が画面の上部になるようにスクロール          |
| `zz`        | カーソル行が画面の中央になるようにスクロール                   |
| `zb`        | カーソル行が画面の下部になるようにスクロール        |
| `z<Enter>`  | カーソル行が画面の上部になるようにスクロール後、行頭に移動     |
| `z.`        | カーソル行が画面の中央になるようにスクロール後、行頭に移動     |
| `z-`        | カーソル行が画面の下部になるようにスクロール後、行頭に移動     |


:::note info
トラックパットでスクロールできる？はい。私もそれしか使っていないです😗
:::



## おわりに
今回はVimでの縦移動についてご紹介しました。
次はいよいよ横移動なわけですが、おそらくVimmerでも全部使っている人はいないだろう！というくらいのキーマップ数があります。


## 宣伝
少しだけ宣伝です！
2025年4月19日（土）にRareTECHの学習交流会が東京で開催されます！
一般の方も一緒に学習できますから、ぜひご参加いただけますと幸いです！

https://connpass.com/event/347287/