『概要』
「擬似Vi-Mode」の所以は、方向キー「←↓↑→」を通常の「hjkl」ではなくて「jkil」としました。これは私の小指が短めで、中指が長めのために選択してみました。恐らく、Vim系列では、このようなキー設定の変更は事実上不可能と推測しています。当初は、zshの.zshrcで使い慣れている「bindkey -e」をベースに、下記の設定から始めました;
- "^J" backward-char
- "^K" down-line-or-history
- "^I" up-line-or-history
- "^L" forward-char
- "^A" beginning-of-line
- "^B" backward-delete-char
- "^D" delete-char-or-list
- "^E" end-of-line
- "^G" expand-or-complete
- "^M" accept-line
- "^U" undo
この変則的なキーマッピングは文字(chr)単位だけの操作だけでしたが、予想以上に快適だったので、「Esc」を使って、語(word)や列(line)の操作をしようとしましたが、小指が短めの私には、「Esc」は遠すぎです。
実は、Karabiner-Elementsにより、下記のキー操作が実現されています;
- スペース・キーを長押ししていると「lコントロール・キー (^)」
- スペース・キーの左右には「コマンド・キー(⌘)」
- また、キャップスロック・キーには(FN)
そこで、Karabiner-ElementsでTerminalについての.jsonを検索すると、"Navigation in Terminal Apps"があったので、これを参考に語(word)や列(line)の操作ができました’
- "tViModoki.2g.json"
- 以降、ViModokiがニックネームとなりました。
- 起動キーは「左コマンド(スペース・キーを長押し)」で、
- 修飾キーは「コマンド・キー(⌘)」
ここまで来ると、「範囲指定: ^oで開始点を設定、終点まで移動」をして、「コピー: ^w」、「削除:^x」、「ペースト:^v」が欲しくなりました。「^w」と「^x」は、下記の2つのサイトを参考に関数で対応しました;
zshで範囲選択・削除・コピー・切り取りするhttps://qiita.com/takc923/items/35d9fe81f61436c867a8
Macがzshになるなら、ZLEを習得するっきゃない!https://dev.classmethod.jp/tool/zsh-zle-introduction/
『.zshrcでのbindkey設定』
## basic bindkey setting
bindkey -d
bindkey -e
## # cursor movement by char/word/line
bindkey '^[j' backward-word # ⎋j: ←.w
bindkey '^j' backward-char # ^j: ←.c
bindkey '^k' down-line-or-history # ^k: ↓.l
bindkey '^i' up-line-or-history # ^i: ↑.l
bindkey '^l' forward-char # ^l: →.c
bindkey '^[l' forward-word # ⎋f: w.→
## # resion & killing
bindkey '^o' set-mark-command # 範囲の開始位置をマーク
bindkey '^x' kill-region
#マークから現在位置までの範囲を削除し、それをキルリングに蓄積.
bindkey '^v' yank
#キルリングの最新の内容を貼り付ける
bindkey '^[v' yank-pop
#キルリングを遡る(Ctrl-yの後にのみ有効)
## bindkey '^[w' copy-region-as-kill # カーソルの左側の語をコピー
## # cursor movement by line
bindkey '^[a' kill-line # ⎋a: ⌦.eol
bindkey '^a' beginning-of-line # ^a: bol.l
bindkey '^[e' backward-kill-line # ⎋e: bol.⌫
bindkey '^e' end-of-line # ^e: l.eol
# bindkey '^y' center-of-line # function center-of-line()
# forward delete for word & char
bindkey '^[d' kill-word # ⎋d: w⌦
bindkey '^d' delete-char-or-list # ^d: c⌦
# backward delete for word & char
bindkey '^[b' backward-kill-word # ⎋b: ⌫w
bindkey '^b' backward-delete-char # ^b: ⌫c
# operation
bindkey '^_' undo # ^_: ⎌
bindkey '^m' accept-line # ^m: ↩︎
『tViModoki.2g.json』
{
"title": "tViModoki.2g.json,
"rules": [
{
"description": "tViModoki.2g.json T=^;⌘a➤⎋a,⌘b➤⎋b,⌘c➤⌘c,⌘d➤⎋d,⌘e➤⎋e,h➤⎋h,⌘j➤⎋j,l➤⎋l,p➤⎋q,q➤',u➤^_,⌘v➤⎋v,⌘x➤⌘x,⌘z➤⌘z.",
"_note0": "^q:quote ^p:push-line ^h:run-help",
"_note1": "rev 2f: 2019-11-11-1820 <-- rev 2e.1: 1370220828.json",
"_note2": "rev 2g: 2019-12-12-2205 alphabetical order",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "a",
"modifiers": {
"mandatory": [
"control",
"command"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "a"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "b",
"modifiers": {
"mandatory": [
"command",
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "b"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "c",
"modifiers": {
"mandatory": [
"control",
"command"
],
"optional": [
"caps_lock"
]
}
},
"to": [
{
"key_code": "c",
"modifiers": [
"left_command"
]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "d",
"modifiers": {
"mandatory": [
"command",
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "d"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "e",
"modifiers": {
"mandatory": [
"control",
"command"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "e"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "h",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "h"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.apple\\.finder$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"command",
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "j"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.apple\\.finder$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "l",
"modifiers": {
"mandatory": [
"command",
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "l"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "p",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "q"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.apple\\.finder$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "q",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "quote"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.apple\\.finder$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "s",
"modifiers": {
"mandatory": [
"control",
"command"
],
"optional": [
"caps_lock"
]
}
},
"to": [
{
"key_code": "s",
"modifiers": [
"left_command"
]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "u",
"modifiers": {
"mandatory": [
"control"
]
}
},
"to": [
{
"key_code": "hyphen",
"modifiers": [
"left_shift",
"left_control"
]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "v",
"modifiers": {
"mandatory": [
"control",
"command"
],
"optional": [
"caps_lock"
]
}
},
"to": [
{
"key_code": "v",
"modifiers": [
"left_command"
]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "x",
"modifiers": {
"mandatory": [
"control",
"command"
],
"optional": [
"caps_lock"
]
}
},
"to": [
{
"key_code": "escape"
},
{
"key_code": "v"
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
},
{
"type": "basic",
"from": {
"key_code": "z",
"modifiers": {
"mandatory": [
"control",
"command"
],
"optional": [
"caps_lock"
]
}
},
"to": [
{
"key_code": "z",
"modifiers": [
"left_command"
]
}
],
"conditions": [
{
"type": "frontmost_application_if",
"bundle_identifiers": [
"^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$",
"^co\\.zeit\\.hyperterm$",
"^co\\.zeit\\.hyper$",
"^io\\.alacritty$",
"^net\\.kovidgoyal\\.kitty$"
]
}
]
}
]
}
]
}
『.zshrcでのzle関数』
### functions for bindkey ######################################################
# #
# https://qiita.com/takc923/items/35d9fe81f61436c867a8
# zshで範囲選択・削除・コピー・切り取りする
# 導入: 2019-12-12-052531
function copy-region() {
zle copy-region-as-kill
REGION_ACTIVE=0
}
zle -N copy-region
bindkey "^w" copy-region
function remove-region() {
# if [[ "$(($REGION_ACTIVE))" -eq 0 ]]; then
# zle backward-kill-word
# else
# zle kill-region
# fi
zle kill-region
}
zle -N remove-region
bindkey "^x" remove-region
# https://dev.classmethod.jp/tool/zsh-zle-introduction/
# Macがzshになるなら、ZLEを習得するっきゃない!
# 2019-12-12-191339 「if [[ 」は駄目だった。
function tab-hokan() {
[[ "${RBUFFER:0:1}" != " " ]] && BUFFER="${LBUFFER} ${RBUFFER}"
zle expand-or-complete
zle redisplay
}
zle -N tab-hokan
bindkey "^g" tab-hokan
『キー操作のリスト』
• vm: "tiny Vi-Modoki based on Navigation in Terminal Apps" •
•• for Terminal.apps with zsh using bindkey -e ••
##### ====== move cursor by a char/line/word =========== #####
# ^j: ←c # ⌘^j: ⤆w ☑︎
# ^k: ↓l #
# ^i: ↑l #
# ^l: c→ # ⌘^l: w⤇ ☑︎
##### === go to (bol|col|eol), long delete (eol|bol) === #####
# ^a: bol⤟ # ^e: ⤠eol
# ^y: col # center-of-line()
# ⌘^a: l⌦eol ☑︎ # ⌘^e: bol⌫l ☑︎
##### ======== delete by a word/char =================== #####
# ⌘^d: w⌦ ☑︎ # ⌘^b: ⌫w ☑︎
# ^d: c⌦ # ^b: ⌫c
##### ======== reginal operation ======================= #####
# ^o: set-mark-command
# ^v: yank # ^v:
# ^[v: yank-pop # ^⌘v: (☑︎)
# ^w: copy-region # copy-region()
# ^x: remove-region # remove-region()
##### ======== etc =========== t.ViM : ☑︎=============== #####
# ^h: run_Help # ^h: ⎋h ☑︎
# ^m: accept-line # ^m: ↩︎
# ⎋q: Push-line # ^p: ⎋q ☑︎
# ⎋': Quote-line # ^q: ⎋' ☑︎
# ^_: undo # ^u: ^_ ☑︎
##### ============================================== #####
『環境』
- OS: Mojave Ver. 10.14.4
- Terminal: Version 2.9.4 (421.1.1)
- zsh 5.7.1 (x86_64-apple-darwin18.2.0)
『感想』
- 初めて「bindkey」にトライできて楽しかった。まるで小学生のころ、「ナイフで鉛筆削り」をした時のことを思い出しました...。お陰で、タッチ・タイピングが戻ってきた。
- Viのvicmdモードに惹かれるが、いっそのこと別途に「⎋」,「^」,「Fn」などを「CapsLock」のようなトグル型にして従来のキーボードと併用するとよいかも。もう少し体力が回復したら工作したいなぁ!
- 今回Karabiner-Elementsを気楽に操作できたのは、「App Store」で購入した「JSON Editor.app」を、通常のエディタの隣に小さく表示するごとに、エラー部分を表示してくれるのだ。お陰で「,」のエラーは簡単に検知は容易!次に多かったのは単なるタッチ・ミスの検出にも大活躍。
- でも、.jsonは長くて読みづらい。孫悟空のような名前のプリプロセッサーのようなシステムがあるらしいので、調べてみたい。
[この記事の履歴]
- 開始 2019-12-14