【hammerspoon】emacs の操作を表示する
このあいだ、ひっさしぶりに emacs を起動してみて、ほんと驚いた。
操作方法を綺麗さっぱり忘れてしまっているのである。
前に使っていた Macbook のディスプレイが割れてしまったころ、しょうがないから Windows のノートに Linux の feren OS というのをぶちこんで使っていた。そのあいだ一ヶ月くらい、ずっと emacs を使っていたと思う。基本操作くらいは指に染みついていると思っていた。染みちゃいねえ!
おそるべきことだ。これが老化なのである。ハゲの進行具合とか下半身の活力とか、そんなのどうでもよくて、覚えたことがツルっと消えて、とっかかりも思い出せない。これがおじさんなのだ。わしゃ隠居したいよ、とほほ。
Hammerspoon で操作方法を表示する
そもそも emacs って、覚えなくちゃならないことが多すぎる。
なにが C-x だよ。なにが M-x だっていってんだよ。
なので、もう org-mode だけしか使わないことにする。覚えなきゃならない範囲を絞るわけだ。dired でさえ特別なコマンドは覚えない。
でもなぁ。emacs ってついついイジりたくなっちゃうんだよなー。
そうじゃなく、そもそも覚えない、というのはどうだ。
すぐに表示できるチートシートがあれば、なにも覚えなくてもいいはず。
ということで、Hammerspoon でチートシートを表示することにした。
チートシートのテキストファイル
手始めにテキストファイルにチートシートを書いた。
筆者の場合はこんな感じ。本当に基本的なことを覚えられていない。
ひとまず、「書類」フォルダのなかに「emacsKey.txt」という名前でぶちこんで置いた。
[ バッファ操作 ]
--------------
全バッファのセーブ ___ C-x s
別名でセーブ ________ C-x C-w
バッファを削除 ______ C-x k
[ 検索 ]
-------
後方検索 ___ C-r
前方検索 ___ C-s
[ コピペ ]
---------
マークをセット ___ C-@
全選択 _________ C-x h
範囲をカット _____ C-w
コピー __________ M-w
貼り付け ________ C-y
[ ウィンドウ ]
------------
現在のウィンドウを消す ___ C-x 0
他のウィンドウを消す _____ C-x 1
[ やり直し ]
------------
アンドゥ ___ C-/
[ org-mode ]
------------
見出し作成 ___ M-ret
次の見出し ___ C-c C-n
前の見出し ___ C-c C-p
項目入れ替え ______ M-↑ M-↓
アスタリスク増減 ___ M-← M-→
項目カット ____ C-c C-x C-w
項目ペースト ___ C-c C-x C-y
Todo ____ Shift-←→
リンク ___ C-c C-l
書き出し __ C-c C-e
ヘッダ候補 __ CM-i
Luaスクリプト
スクリプトは以下のような感じにした。
emacsMode = hs.hotkey.modal.new()
emacsMode:bind('cmd', '/', 'cheatSheet', function()
local c = require("hs.canvas")
sheet = c.new{ x = 100, y = 100, h = 420, w = 900 }:show()
sheet[1] = { type = "rectangle",
fillColor = { black = 1.0, alpha = 0.8} }
sheet[2] = { type = "text", text = '',
textColor = { white = 1.0 },
textFont = "Osaka-Mono",
textSize = 15.0,
textAlignment = "left",
frame = { x = "0.0", y = "0.0", h = "1.0", w = "0.33" },
padding = 5.0, }
sheet[3] = { type = "text", text = '',
textColor = { white = 1.0 },
textFont = "Osaka-Mono",
textSize = 15.0,
textAlignment = "left",
frame = { x = "0.33", y = "0.0", h = "1.0", w = "0.33" },
padding = 5.0, }
sheet[4] = { type = "text", text = '',
textColor = { white = 1.0 },
textFont = "Osaka-Mono",
textSize = 15.0,
textAlignment = "left",
frame = { x = "0.66", y = "0.0", h = "1.0", w = "0.33" },
padding = 5.0, }
local leftText = hs.execute("cat ~/Documents/emacsKey.txt | sed -n 1,18p")
sheet[2].text = leftText
local centerText = hs.execute("cat ~/Documents/emacsKey.txt | sed -n 20,27p")
sheet[3].text = centerText
local rightText = hs.execute("cat ~/Documents/emacsKey.txt | sed -n 29,44p")
sheet[4].text = rightText
end, function()
if sheet then
sheet:delete()
end
end)
function appWatch(name, event, app)
if event == hs.application.watcher.activated then
if name == 'Emacs' then
emacsMode:enter()
else
emacsMode:exit()
end
end
end
appWatcher = hs.application.watcher.new(appWatch)
appWatcher:start()
emacs をアクティブにした状態で[ command ] + [ / ]を押すと、押している間ずっとチートシートを表示し続ける。キーから指を上げると表示が消える。
hs.hotkey.modal
hs.hotkey.modal というモジュールが面白い。
ドキュメントによると、こんな書きかたが出来るのだ。
hs.hotkey.modal:bind(mods, key, message, pressedfn, releasedfn, repeatfn)
引数に、モディファイキー、組み合わせのキー、メッセージ、キーを押した時の関数、キーを離した時の関数、リピートした時の関数を設定できるのである。
上記の場合ならモディファイキーは command だ。
モディファイキーを複数指定する場合はハイフンでつなぐ。例えば :bind('cmd-alt-ctrl'
という感じ。
組み合わせるキーは、だいたいキーを押した時に表示される文字でいい。その後のメッセージはなくてもいいが、設定しておくと、キーバインドが押された時に hs.alert.show で表示してくれる。
そのあとの pressedfn で、上記のスクリプトは hs.canvas を使ってチートシートのテキストを表示している。その次の releasedfn で作成した hs.canvas を削除することにした。
repeatfn は今回必要ないので書いていない。必要ない関数は省いてもいいことになっている。
hs.canvas
pressedfn の部分で hs.canvas「 c 」から、sheet という新規の canvas オブジェクトを作成している。
canvas オブジェクトは、lua のテーブルみたいな構造だろうと思われる。
作成には x, y の座標と、h , w という縦横の長さを決めてやる必要がある。
背景となる最初のエレメントを、sheet[1] という形で定義する。このエレメント、というやつもテーブルらしく、各エレメントがレイヤーのように重なっていく。sheet[1] は長方形を意味する rectangle というタイプにして、背景は黒、透明度を 0.8 とした。枠線はデフォルトの 1px の黒である。
次にテキストボックスとなる sheet[2] を定義する。タイプはテキスト、表示する内容はとりあえず空にしておくため text = ''
と定義した。他にもフォントやテキストサイズなどを設定した。
テキストボックスの位置と大きさは frame で設定する。x, y, h, w に入る数値はパーセントである。0.2 なら 20 パーセント、1 で 100 パーセントとなる。
sheet[2]は左に配置し、同じように作った sheet[3] は真ん中、sheet[4] は右に置くという段組みになっている。
チートシートのテキストは hs.execute でシェルコマンドを実行し、取得している。
エレメントはテーブルなので、 sheet[2].text = 'テキスト'
というふうに代入できる。
仮に sheet[1] の透明度を、なにかのタイミングで変更するとしたら sheet[1].fillcolor.alpha = 0.3
などと書くことになると思う。
生成した sheet は、キーを離した時に実行される次の function で削除される。
sheet:delete()
というメソッドを使っている。
hs.canvas と hs.hotkey.modal というモジュールの組み合わせは使い出があって、いろいろ面白い。
hs.console というモジュールで hammerspoon のコンソールを出力できるので、それを表示してみる。
consoleMode = hs.hotkey.modal.new('ctrl', '-')
consoleMode:bind('', 'escape', function()
consoleMode:exit()
end)
flip = nil
function consoleMode:entered()
local c = require("hs.canvas")
flip = c.new{ x = 1100, y = 200, h = 500, w = 320 }:show()
flip[1] = { type = "rectangle",
fillColor = { black = 1.0, alpha = 0.8} }
flip[2] = { type = "text", text = '',
textColor = { white = 1.0 },
textFont = "07YasashisaGothic",
textSize = 14.0,
textAlignment = "left",
frame = { x = "0.0", y = "0.0", h = "1.0", w = "1.0" },
padding = 5.0, }
local consoleText = hs.console.getConsole()
local f = io.open(os.getenv("HOME").."/Desktop/output.txt", "w")
f:write(consoleText)
f:close()
local consoleShow = hs.execute("tail -n10 ~/Desktop/output.txt")
flip[2].text = consoleShow
end
function consoleMode:exited()
flip:delete(0.5)
end
[ control ] + [ – ]でコンソールの最終 10 行を表示し、[ esc ]で表示を消す。
コンソールはデスクトップに、テキストファイルにして出力している。
なんかチートシートの表示でめっちゃエラー出てる。
出てるけど、ひとまずは動くから。動きますので。
なんかでも、これはどうしようもないエラーくさいんだよなぁ。