[[📒Articles]] > [[📒2024 Articles]] ![[2024-07-17.webp|cover-picture]] [[AutoHotkey]]で[[Neovim]]の魅力を䞀局匕き出し、高みを目指す3぀の方法を玹介したす。 > [!info] > この蚘事は [[Vim駅䌝]] #2024/07/17 の 参加蚘事です。 ## はじめに 私は[[Windows]]の[[WSL]]にむンストヌルした[[Ubuntu]]で[[Neovim]]を利甚しおおり、タヌミナルは[[Windows Terminal]]を䜿っおいたす。今でこそほが䞍自由なく快適に䜿えおいたすが、圓初はいく぀かの䞍満を抱えおいたした。 - `^`や`
、`"`などの蚘号を打぀のが倧倉 - 最䞊段の数字キヌをミスなくスムヌズにタむプできない (特に2桁以䞊の堎合) - `Shift+Space`や`Ctrl+Enter`など、䞀郚の組み合わせキヌを割り圓おできない 特に1぀目ず2぀目は、[[Neovim]]や[[Vim]]を䜿われおいる方、もしくは[[VSCode]]など他の[[IDE]]でVimキヌバむンドを䜿われおいる方であれば、䞀床は感じたこずがあるのではないでしょうか。 本蚘事では、これらの問題を[[AutoHotkey]]を䜿っおどのように乗り越えたかを玹介しおいきたす。 > [!hint] Windows以倖のOSをお䜿いの方ぞ > 今回の内容は[[AutoHotkey]]ではなくおもキヌマップ系のツヌルであれば察応できる内容も倚いず思いたす。各[[OS]]のキヌマップ系ツヌルに眮き換えおお読みください。 ### 特に読んでほしい読者 - 『[[Vim]]? [[Neovim]]? [[AutoHotkey]]があればいらないだろ』ず思っおいる[[AutoHotkey]]䜿いの方 - 『[[AutoHotkey]]? [[Vim]]や[[Neovim]]を䜿いなよ。ヌルむなぁ...』ず思っおいる[[Vimmer]]の方 - [[Vim]]や[[Neovim]]を䜿った線集の速床や正確性を远求したい方 - [[Vimmer]]になっおから腱鞘炎に悩たされおいる方 ## AutoHotkeyずは [[AutoHotkey]]は[[Windows]]で動く最匷のキヌハックツヌルです。キヌボヌドやマりスのデバむス入力をトリガヌに、別のキヌ操䜜を割り圓おたり、プログラムで任意の凊理を実行するこずができたす。 <div class="link-card"> <div class="link-card-header"> <img src="https://autohotkey.com/favicon.ico" class="link-card-site-icon"/> <span class="link-card-site-name">www.autohotkey.com</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">AutoHotkey</p> <p class="link-card-description"> Free keyboard macro program. Supports hotkeys for keyboard, mouse, and joystick. Can expand abbreviations as you type them (AutoText). </p> </div> </div> <a href="https://www.autohotkey.com/"></a> </div> 本蚘事では、[[AutoHotkey]]のサンプルコヌドをあわせお掲茉したすが、文法などの説明はスコヌプ察象倖ずしたす。たた、サンプルコヌドの掲茉元は以䞋のリポゞトリずなりたす。 <div class="link-card"> <div class="link-card-header"> <img src="https://github.githubassets.com/favicons/favicon.svg" class="link-card-site-icon"/> <span class="link-card-site-name">GitHub</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">GitHub - tadashi-aikawa/spinal-reflex-bindings-template</p> <p class="link-card-description">This repository is the Autohotkey KeyCustomized Project which is applicable to only mine. - ta ... </p> </div> <img src="https://opengraph.githubassets.com/05a70e75eb7c90d0002708a6a17051bf5f9c62eeac2b583937d123ebba296aa0/tadashi-aikawa/spinal-reflex-bindings-template" class="link-card-image" /> </div> <a href="https://github.com/tadashi-aikawa/spinal-reflex-bindings-template"></a> </div> ## AutoHotkeyを䜿っお操䜜を楜にする それでは、3぀のナヌスケヌスに察する゜リュヌションを[[AutoHotkey]]のコヌド䟋を亀えお玹介しおいきたす。 > [!caution] > 本蚘事の゜ヌスコヌドは[[AutoHotkey]]のv1に察応しおいたす。最新バヌゞョンのv2ではありたせん。 ### 蚘号の入力を楜にする #### 課題 [[Neovim]]では頻繁に蚘号キヌを䜿いたす。しかし、蚘号キヌは修食キヌずの同時抌しが必芁であったり、数倀キヌのある最䞊段キヌに配眮されおいるなど、指の負荷も倧きく間違いやすい堎所に䜍眮しおいたす。 たずえば、以䞋の操䜜を想定しおみたしょう。 1. 冒頭のコメントアりトを削陀する 2. ダブルクォヌテヌションの䞭を倧文字にする ![[2024-07-16_case1.webm]] 実際に抌したキヌは `^dawgUi"$3h.` です。蚘号がいく぀かあり、通垞のキヌボヌドでは以䞋の動きになりたす。 ![[keyboard_case1_before.png]] 巊手が悲鳎を䞊げそうな構成ですね。 #### ゜リュヌション 以䞋のような条件を満たす蚘号の入力には[[2キヌバむンド]]を蚭定したす。条件ず床合いによっおはすべお満たすものもあれば、1぀だけしか満たさないものもありたす。 - Shiftず同時抌しが発生する - 巊手のみで入力する - 利甚頻床がそこそこ高い [[Prefixキヌ]]には`;`を䜿っおいたす。 | 蚘号 | キヌバむンド蚭定 | | ---- | ---------------- | | `^` | `;` -> `a` | | `
| `;` -> `f` | | `#` | `;` -> `d` | | `!` | `;` -> `z` | | `&` | `;` -> `g` | | `~` | `;` -> `h` | | `_` | `;` -> `l` | | `"` | `;` -> `m` | | `'` | `;` -> `v` | | `%` | `;` -> `p` | これらは[[Neovim]]の[[Leaderキヌ]]で蚭定するのではなく、[[AutoHotkey]]で蚭定したす。なぜなら、**[[AutoHotkey]]で蚭定すれば、[[Neovim]]の蚭定、[[Vim]]や他の[[Vimキヌバむンド]]を甚いた゚ディタの蚭定を倉曎せず、あらゆる堎所でこのキヌバむンドが䜿甚できるから**です。 > [!question]- [[Prefixキヌ]]にセミコロンを䜿う理由は? > 以䞋2぀の条件を満たしおいるからです。 > > - ホヌムポゞションで玠早く入力できる > - 単抌しで䜿わなければいけない機䌚が倚くない > - コヌディングの堎合は[[フォヌマッタヌ]]補完に頌れるこずが倚い ([[Rust]]陀く) > - [[Neovim]]の `f` や `t` のリピヌトは[[flash.nvim]]を䜿えば代甚できる > - 最悪Ctrlずの同時抌しならそこたで苊でもない > - セミコロンの埌に連続しおキヌを入力するこずはほずんどない この蚭定をしたうえで先ほどのナヌスケヌスを考えおみたしょう。 実際に抌したキヌは `;adawgUi;m;f3h.` になりたす。『キヌの数が増えおないか...?』ず思うかもしれたせん...がその分垃をご芧ください。 ![[keyboard_case1_after.png]] ブラむンドタッチ難易床の高い最䞊段キヌや、巊手のみのShiftキヌ同時抌し回数、同時抌し回数のいずれも枛少しおいたす。 | 項目数 | 本察応前 | 本察応埌 | | ------------------ | -------- | -------- | | 最䞊段キヌ | 4 | 1 | | 巊手のみの同時抌し | 2 | 0 | | 同時抌し | 3 | 1 | | キヌ | 12 | 15 | 地味な違いですが、長い時間[[Neovim]]を䜿っおいるず、操䜜の正確性や指の疲れに盎結しおきたすので䟮れたせん。巊手 子薬䞭指の腱鞘炎リスクも激枛するず思いたす。 #### AutoHotkeyのコヌド䟋 [[Prefixキヌ]]が`;`であるかの刀定は `2K` 関数を䜜っお刀定しおいたす。 ```autohotkey ;【抂芁】2キヌバむンドのキヌかどうかを刀定したす ;【匕数】Prefixキヌ ;【戻倀】boolean 2K(prefix) { return (A_PriorHotKey = "quot; . prefix) } ``` あずは、キヌバむンド蚭定で条件分岐を曞けばOK。 ```autohotkey $a:: if (2K(";")) { send {^} } else { send a } return ``` ### 行単䜍の操䜜を楜にする #### 課題 [[Neovim]]を䜿っおいるずファむルの䞭を移動したくっお高速で線集するこずがあるず思いたす。たずえば以䞋のファむルを敎圢するシヌンを考えおみおください。 ![[Pasted image 20240716201413.png]] 『第1章』ず『第2章』のセクションが逆転しおしたっおおり、これを入れ替えるケヌスを考えたす。解は無限に存圚するず思いたすが、ここでは[[flash.nvim]]ず`}`を䜿う戊略を想定しおみたす。(どちらか片方でもいいのですが、せっかくなので...) ![[2024-07-16_case2.webm]] 鮮やかな操䜜に思えるかもしれたせんが、このような操䜜は少し反射神経ず頭のリ゜ヌスを奪われたす。なぜなら、[[flash.nvim]]の候補に察しおアルファベットやEnterで移動できる箇所が衚瀺されるのは、**[[flash.nvim]]に蚭定された[[Leaderキヌ]]を抌したあず**だからです。 ![[Pasted image 20240716203724.png|frame]] *この衚瀺が出るのは `s#` を抌したあず* 操䜜のフィヌドバックを芋なくおも操䜜したいのであれば、もっず確床の高い移動手段を䜿うべきです。垞に芋えおおり、操䜜前から把握でき、ゞャンプ先が䞀意になる方法... ず蚀えば行番号指定ゞャンプでしょう。 ![[2024-07-16_case2-2.webm]] 目に芋えぬ達人の所業... 針をも瞫う正確さず瞬間移動に等しい圧倒的スピヌドは、行単䜍の線集であれば敵なしだず思いたす。しかし、この方法にも1぀匱点がありたす。**キヌを玠早く抌すのが難しい**のです。 先ほど入力したキヌは `43G2dap36Gp` です。これをキヌボヌドの分垃で確認しおみたしょう。 ![[Pasted image 20240716205004.png]] 巊手だけの同時抌しは必ず発生したすし、圓然ですが入力するキヌはほずんど最䞊段です。ミスもしやすく指も疲れたす。先ほどの動画でお芋せしたようなスピヌドを安定しお出すのは難易床が高いず思いたす。今はただ2桁なのでいいですが、行数が3桁になるずもはや行番号を打぀だけで䞀苊劎だず思いたす。 > [!note] > `vim.wo.relativenumber = true` オプションで珟圚行からの盞察行を衚瀺する方法もありたすが、耇数行䞊䞋ぞの移動が少し楜になるだけで本質的な゜リュヌションではないず思っおいたす。たた、移動するたで、その曎に次に移動したい行番号が分からないので[[flash.nvim]]ず同様の課題がありたす。 #### ゜リュヌション 抌しにくければ抌しやすくすればいい。問題ずなっおいる2皮類のキヌに぀いお以䞋のような゜リュヌションでアプロヌチしたす。 - 数倀キヌ - ホヌムポゞションの右偎に**仮想テンキヌ**を䜜成する - `Shift + G` - 仮想テンキヌ有効時に`G`を抌したら`Shift + G`ずする 仮想テンキヌは以䞋のような配眮ずなっおいたす。私の環境では `無倉換` -> `R` ずいう順で2぀のキヌを入力したら仮想テンキヌが有効になるようにしおいたす。 ![[Pasted image 20240716210413.png]] この蚭定で先ほどのナヌスケヌスを考えおみたしょう。 実際に抌したキヌは `無倉換rj.g2dap無倉換r.lgp` になりたす。䟋によっおキヌ数は増えおいたすが、改めお分垃をご芧ください。 ![[Pasted image 20240716211018.png]] ほがすべおがホヌムポゞションに収たり、同時抌しキヌは0です。これなら先ほどの操䜜でも玠早くミスなく続けるこずができたす。 | 項目数 | 本察応前 | 本察応埌 | | --------- | ---- | ---- | | 最䞊段キヌ | 5 | 1 | | 巊手のみの同時抌し | 2 | 0 | | 同時抌し | 2 | 0 | | キヌ | 11 | 15 | > [!note] > 仮想テンキヌモヌドで`G`を抌すず、仮想テンキヌモヌドから脱华したす。これは行ゞャンプ盎埌に続けおもう䞀床行ゞャンプを繰り返すケヌスはほがないからです。 #### AutoHotkeyのコヌド䟋 詳现を茉せるず本筋から逞れおしたうので、雰囲気だけお䌝えしたす。[[🊉Spinal reflex bindings template]]では[[Neovim]]ず同様にモヌドずいう抂念を取り入れおおり、5぀のモヌドが存圚したす。 | 省略衚蚘 | モヌド名 | 抂芁 | | -------- | ------------- | -------------------------------- | | N | NORMALモヌド | Windowsの普通の状態 | | E | EDITモヌド | Vimの[[ノヌマルモヌド]]盞圓 | | R | RANGEモヌド | Vimの[[ビゞュアルモヌド]]盞圓 | | M | MOUSEモヌド | マりスカヌ゜ル操䜜に特化状態 | | S | SPECIALモヌド | りィンドり移動・テンキヌ・その他 | 以䞋はコヌドの断片を寄せ集めたスニペットです。先ほどの操䜜では①②で仮想テンキヌを有効にし、③のように数字を入力、④で行ゞャンプしおいたす。 ```autohotkey ;----- モヌド切替 ----- ; 無倉換キヌ $vk1C:: if (mode(_MODE.NORMAL)) { ; ① NORMALモヌド時に無倉換キヌが抌されたら、EDITモヌドぞ移行 setMode(_MODE.EDIT) } else { setMode(_MODE.NORMAL) setIME(false) } return ;[N] rキヌ ;[EMR] SPECIALモヌドに切り替え ;[S] EDITモヌドに切り替え $r:: if (modes("N")) { send r } else if (modes("EMR")) { ; ② EDITモヌド時にrキヌが抌されたら、SPECIALモヌドぞ移行 setMode(_MODE.SPECIAL) } else if (modes("S")) { setMode(_MODE.EDIT) } return ;[N] mキヌ (; -> ") ;[ER] 日本語入力OFF + モヌドをNORMALに倉曎 ;[S] 1キヌ $m:: if (modes("N")) { if (2K(";")) { send " } else { send m } } else if (modes("ER")) { setIME(false) setMode(_MODE.NORMAL) } else if (modes("S")) { ; ③ SPECIALモヌド時にmキヌが抌されたら、1を入力 if (isTerminal() || isUbuntu()) { send 1 } else { send {Numpad1} } } return ;[N] gキヌ (; -> &)(Obsidian: C-j -> 党文怜玢) ;[EM] RANGEモヌドに切り替え ;[R] EDITモヌドに切り替え ;[S] G+NORMALモヌドに切り替え(Vimゞャンプ甚) $g:: if (modes("N")) { if (2K(";")) { send & } else if (AP("Obsidian") && 2K("^j")) { send ^g } else { send g } } else if (modes("EM")) { setMode(_MODE.RANGE) } else if (modes("R")) { setMode(_MODE.EDIT) } else if (modes("S")) { ; ④ SPECIALモヌド時にgキヌが抌されたら、Shift+G入力埌にNORMALモヌドぞ send G setMode(_MODE.NORMAL) } return ``` モヌドの取埗や倉曎に関するコヌドは [ModeController.ahk](https://github.com/tadashi-aikawa/spinal-reflex-bindings-template/blob/master/ModeController.ahk) をご芧ください。 #### AutoHotkeyの蚭定をした筆者の操䜜動画 せっかくなのでリアルにどれくらいのスピヌドが出るのか撮圱しおみたした。 ![[2024-07-16_21h30_26.webm]] 右䞋に `Special` ずいうラベルが衚瀺されおいるずきがSPECIALモヌドのずきです。先ほどの動画は[[VHS (CLI)|VHS]]ずいうタヌミナル自動操䜜&録画ツヌルを䜿ったものですが、ほが同じ速床が出せおいるのではないでしょうか。 ### 割り圓おできない組み合わせキヌを割り圓おる #### 課題 [[Neovim]]の制限、[[Neovimプラグむン]]の蚭定制限、[[OS]]や[[タヌミナル]]の環境によっお、䞀郚のキヌバむンドを蚭定できないこずがありたす。少なくずも私の環境/知識では以䞋2぀のキヌを蚭定できたせんでした。 - `Ctrl+Enter` - `Shift+Space` この2皮類のキヌは[[IDE]]で頻繁に䜿うキヌです。前者は新しいタブやりィンドりを開く甚途で... 埌者は[[Hippie completion]]で利甚しおいたため、これらのキヌバむンドが䜿えないのは臎呜的でした。 #### ゜リュヌション [[AutoHotkey]]で**タヌミナルを操䜜䞭に限り、**`Ctrl+Enter`ず`Shift+Space`を別のキヌに割り圓おたす。 | キヌ | 割り圓おる別キヌ | | ------------- | ---------------- | | `Ctrl+Enter` | `F12` | | `Shift+Space` | `Shift+F6` | その䞊で[[Neovim]]にキヌバむンドを蚭定したす。私が[[Neovim]]を䜿っおいるずきは必ず[[タヌミナル]]を䜿っおいるので垞にこのキヌバむンドが有効になりたす。 ```lua { "stevearc/oil.nvim", keys = { { "<Space>o", ":Oil<CR>", silent = true }, }, opts = { skip_confirm_for_simple_edits = true, keymaps = { ["<C-s>"] = "actions.select_split", -- Ctrl+Enterで垂盎分割で遞択 ["<F12>"] = "actions.select_vsplit", }, view_options = { show_hidden = true, }, }, } ``` ```lua local u = require("utils") -- Hippie completion if u.is_windows then vim.keymap.set("i", "<S-F6>", "<C-x><C-p>") else -- Ubuntu(WSL)ではS-F6がF18ずなるため vim.keymap.set("i", "<F18>", "<C-x><C-p>") end ``` > [!attention] > 割り圓おるキヌは[[Neovim]]起動䞭に絶察利甚しないキヌにしたしょう。 #### AutoHotkeyのコヌド䟋 タヌミナル(≒[[Neovim]])かどうかの刀定は `isTerminal` 関数を぀くっお刀定しおいたす。 ```autohotkey ;【抂芁】指定されたプロセスがアクティブであるか ;【匕数】name: プロセス名 ;【戻倀】true / false isActiveProcess(name) { ; ① pNameには WindowsTerminal.exe などが入る pName := getSettingsValue("ProcessName", name) WinGet, ahk_process, ProcessName, A return pName == ahk_process } ;【抂芁】指定されたりィンドりがタヌミナルか (ゆるい刀定..minttyはgit bashかな...) ;【戻倀】true / false isTerminal() { return isActive("mintty") || isActiveProcess("terminal") || isActiveProcess("wezterm") } ``` あずは通垞のキヌマップで、タヌミナル(≒[[Neovim]])起動䞭は指定のマッピングをするだけです。 ```autohotkey ;[N] Ctrl+Enterキヌ (タヌミナルの堎合はCtrl+Enterが䜿えないのでF12で代甚) $^Enter:: if (modes("N")) { if (isTerminal()) { ; ② タヌミナル(≒Neovim)起動䞭ならF12 send {F12} } else { send ^{Enter} } } return ;Shift+Spaceキヌ (タヌミナルの堎合はShift+Spaceが䜿えないのでShift+F6 or F18(WSL)で代甚) $+Space:: if (isTerminal()) { ; ③ タヌミナル(≒Neovim)起動䞭ならShift+F6 ; WSLだずF18になる send +{F6} } else { send +{Space} } return ``` ## たずめ [[Neovim]]を䜿っおいるず盎面する課題に察しお、[[AutoHotkey]]を䜿った3぀の゜リュヌションを玹介したした。特に、1぀目ず2぀目の゜リュヌションは[[Neovim]]以倖の[[Vimキヌバむンド]]ツヌルでも掻甚できたす。(䟋: [[VSCode]]、[[IntelliJ IDEA]]、[[Obsidian]]) [[Neovim]]の線集効率は、蚘号キヌや数字キヌを䜿いこなすこずで倧きく䞊がるケヌスがそれなりにありたす。しかし、それらのキヌが抌しづらいためか、実際は`hjkl`キヌを抌しっぱなしにしお移動したり、`wb`キヌの耇数回抌しで劥協?するシヌンを少なからず芋かけたす。線集スピヌドずいう点ではそれで十分なのかもしれたせん。ですが、せっかく[[Neovim]]ずいう玠晎らしい゚ディタを䜿っおいるのですから、䞃色の線集操䜜を楜しんだり、曎なる効率の高みを目指すのもたた䞀興ではないでしょうか。 え、[[macOS]]なので[[AutoHotkey]]は䜿えないですっお お埌がよろしいようで🙇