Visual Studioで複数のカーソルを同時に操る

:::note info
この記事は[GCC Advent Calendar 2024](https://adventar.org/calendars/10768)の11日目の記事です
:::

# はじめに
Visual Studioで必要な場所にカーソル(キャレット)を複数配置して作業効率を上げる方法を紹介します。
VSCodeを使っていた時に見つけた便利ショートカットをVisualStudioでも使えないか調べた結果、同等の機能があったので合わせて紹介します。

# カーソルを増やす方法
複数のカーソルを操作する方法を「マルチカーソル」や「マルチキャレット」と呼ぶそうです。
## 縦に増やす
`Shift+ALT+↑`で現在選択されているカーソルの一行上に、`Shift+ALT+↓`で現在選択されているカーソルの一行下にマルチカーソルを追加します。
また、`ALT+左クリック`長押しでマウスをスライドしても可能です。
ちなみに`Shift`を押している状態なら選択範囲を縦に拡大でき、選択の最後の位置がマルチカーソル化されます。

## 任意の位置に増やす
`ALT+Ctrl+左クリック`で左クリックした場所にカーソルを追加できます。
この操作なら同じ行にも追加できます。

## 同じ文字の場所に増やす
こちらはVScodeで便利だと思っていた機能で、しっかりVisualStudioにも存在してました。(ただショートカットキーが使いにくい)
増やしたい文字を選択して`Alt+Shift+.(ピリオド)`を押すと次の同じ文字の場所にカーソルが追加されます。
また、`Alt+Shift+:`で同じファイル内の一致している文字全てにカーソルを追加できます。
VScodeでいうCtrl+Dにあたる機能で、選択範囲と同じ文字の場所にカーソルを追加できるというもの。慣れると頻繁に使うのに3つのキー同時押しは使いづらかったので私はキーマップを変更して`Ctrl+D`と`Ctrl+Shift+L`に変更しています。
後述しますがこれがなかなかに便利。

# マルチカーソルを使いこなす
選択範囲を直接変更するのであれば検索を利用した置換や、その他機能を使って実現することは可能ですがマルチカーソルの魅力は一致している部分がなくても一気に編集できるという点です。

---
[任意の位置に増やす](#任意の位置に増やす)方法を使うと、例えば複数の関数に同じ引数を入れることが可能です。
![multicaret0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/5819e088-7ecb-6e9a-283e-bb5ed9b8369b.gif)
個人的にこの方法はあまり使ったことがありません。

一番よく使うのは同一文字列にマルチカーソルを割り当てられる`Alt+Shift+.`ショートカットだと思います。
例えば、`private`アクセス修飾子を一部`public`にしたい場合や、指定した場所をコメント化/コメント解除したい場合に使えます。
![multicaret1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/5c7bd451-96cf-9ab4-557b-556218516767.gif)
(結局一致している部分を書き換えてますが...)

## 組み合わせ技
マルチカーソル状態で普通のカーソル移動操作をすることでさらに柔軟な操作ができるようになります。
例えばメンバ変数の最初にアンダースコアを記入したいという場合、次の操作をすることで一気に編集できます。
1. `private`の部分を範囲選択
1. `Alt+Shift+.`で必要部分までマルチカーソルを作成
1. `Ctrl+ →`[^0]を二回押してでカーソルを変数名の前まで移動
1. `_`を入力

`private 型 変数名;`の形であれば全て一気に変更できます。
![multicaret2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/87850685-a62c-0ac2-dcab-9078b59f53ea.gif)
この時、同一文字を選択しなくても任意の位置にマルチカーソルを挿入する方法を使えばいいじゃないかという考えもありますが、作業を効率化しようと考えるとマウスに持ち替える動作がだんだん億劫になってきます。なのでこのように同じ法則がある場面であれば同一文字を利用してマルチカーソルを挿入したほうが早くなります。

## 発展
同じような場面ですが、private変数のカプセル化プロパティを実装したい場合、`Alt+Enter`から生成するのもいいですがマルチカーソルならもっと柔軟に書けます。
`Alt+Enter`からやると次のようになるはずです。(設定によって異なるかも)
```c#
private int hoge;
public int Hoge { get => hoge; set => hoge = value; }
```
読み込み専用にしたい場合や、get private setと実装したい場合にはマルチカーソルが有効です。
例えば次のような書き方でプロパティを使用したカプセル化をしたい場合の操作は以下の通りです。
```c#
private int hoge;
public int Hoge => hoge;
```
1. プロパティを実装したい変数の部分を全てコピーして下にペースト
1. ペーストした場所の`private`を選択して`Alt+Shift+.`でマルチカーソルを作成
1. `public`に変更
1. `Ctrl+ →`を二回押して変数名の最初の場所へ移動
1. `Ctrl+Shift+ →`を一回押して変数名を全て選択
1. `Ctrl+C`でコピー
1. `←`を一回押してカーソルを変数名の最初に戻す
1. `Shift+ →`を一回押して頭文字を選択
1. `Ctrl+Shift+U`[^1]で大文字に変換(パスカルケース)
1. `End`を押して全てのカーソルを最後へ移動
1. `←`を押してセミコロンの前へ移動
1. `=>`を入力
1. `Ctrl+V`でペースト

これで目的の形になります。
かなり丁寧に書いたため工程が多くなっていますが、多分5個のプロパティを手作業で書くより早くできると思います。
![Videotogif (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/1d6abbee-35af-870c-e652-790f05c9b3be.gif)

# コピー＆ペースト
マルチカーソル状態でコピー＆ペーストを利用すると通常と異なる動作をします。
## マルチカーソルでコピー、シングルカーソルでペースト
画像のようにマルチカーソルでコピーして、一つのカーソルの状態でペースト場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/958bb42d-b252-097d-aba1-04613baf84f2.png)
複数の行に分けて貼り付けられます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/4b477fcf-4cb3-26ea-d0c3-32e62518c824.png)

# マルチカーソルでコピー、マルチカーソルでペースト
コピーしたときのカーソルの数と、ペーストするときのカーソルの数が同じであればカーソルの順番に従ってペーストされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/56e7f6a8-4bc8-5c8e-d54b-f8a6a19090d8.png)
カーソルの数が異なればカーソルの数分ペーストを繰り返します。
なお、ペースト前のカーソルが複数の行に分かれてあった場合ペースト後に改行されます。
(画像はカーソルを二つ用意してペーストしました。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/63961e66-6f95-98a7-b81e-e93f913ebcda.png)

# シングルカーソルでコピー、マルチカーソルでペースト
先ほどのABCD...の文字列から`ABCDEF`をコピーして、マルチカーソルでペーストした場合、それぞれの位置にペーストされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624984/6657157f-7560-080a-5b3a-69104781ae81.png)

# その他ショートカット
マルチカーソルを扱うためのショートカットを一覧にしておきます。
|ショートカット|機能|
|-|-|
|Sift+ALT+↑|現在のカーソルの上に追加|
|Sift+ALT+↓|現在のカーソルの下に追加|
|ALT+左クリック|クリックした位置に追加|
|ALT+Shift+左クリック|選択した範囲の最後に追加|
|ALT+Shift+.|次の一致文字列の場所に追加|
|ALT+Shift+:|全ての一致文字列の場所に追加|
|ALT+Shift+,|直前に追加したカーソルを削除|
|ALT+Shift+/|最後のカーソルを次の一致文字列へ移動|
|なし|次のセカンダリカーソルをプライマリカーソルへ|
|なし|前のセカンダリカーソルをプライマリカーソルへ|

# まとめ
少しクセのある機能なので練習が必要かもしれませんが、これらの操作を無意識に使えるようになると作業効率が格段に上がります。
使っていくうちに今回紹介した場面以外の使いどころも見つかると思うので試してみてください。

[^0]: `Ctrl+ →`は単語や記号単位でカーソルを移動させるショートカットです。
[^1]: `Ctrl+Shift+U`は選択している範囲を大文字に変換できるVSのショートカットキーです。小文字へは`Ctrl+U`で変換可能。