Emacsのキーバインドは複雑で、テキストで一覧表示されてもなかな覚えられなくて困っていました。
そこでEmacsのキーバインドを図示するrubyスクリプトを作ってみました。
使い方
- M-x help b でキーバインド一覧を表示させます
- そのテキストをコピペして、src.txtみたいな名前で保存します
- 続きをよむ、にあるソースコードをemacs_keybind.rbみたいな名前で保存します。
- 下のようにコマンドを実行します。
# asciiキーボード配列で出力 emacs_keybind.rb -k ascii src.txt > keyboard.html # 日本語キーボード配列で出力 emacs_keybind.rb -k japanese src.txt > keyboard.html # はてなダイアリーに乗せられる形式で出力 emacs_keybind.rb -k japanese -f hatena src.txt > keyboard.hatena
人のEmacsキーバインドを一度見てみたいなあ、とずっと思っていました。
はてなダイアリー等にのっけてくれたらとてもうれしいです。
ツールの不満
- 生成されるキーバインドのhtmlが横に大きすぎて一覧出来ない。もっと横に圧縮して表示できないものか・・。
- 本当はこのコマンドの起動から、browse-urlによるブラウザの立ち上げまで、Emacsから実行できるようにしたいのだけど方法が分からない・・。
ソースコード
#! ruby -Ku require 'optparse' Version = "0.0.1" Header = <<EOF <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title></title> </head> <body> <p> EOF Footer = <<EOF </p> </body> </html> EOF HeaderHatena = <<EOF **Emacsキーバインド EOF KeyboardAscii = [ # ESC 〜 DEL [ ['ESC'], ['F1'], ['F2'], ['F3'], ['F4'], ['F5'], ['F6'], ['F7'], ['F8'], ['F9'], ['F10'], ['F11'], ['F12'], ['INS'], ['DEL'], ], # 半角/全角 〜 Backspace [ ['`~', %w(` ~)], ['1!', %w(1 !)], ['2@', %w(2 @)], ['3#', %w(3 #)], ['4$', %w(4 \$)], ['5%', %w(5 %)], ['6^', %w(6 ^)], ["7&", %w(7 &)], ['8*', %w(8 \*)], ['9(', %w(9 \\\()], ['0)', %w(0 \\\))], ['-_', %w(- _)], ['= +', %w(= \+)], ['BS'], ], # TAB 〜 RET [ ['TAB', %w(TAB)], ['Q', %w(q Q)], ['W', %w(w W)], ['E', %w(e E)], ['R', %w(r R)], ['T', %w(t T)], ['Y', %w(y Y)], ['U', %w(u U)], ['I', %w(i I)], ['O', %w(o O)], ['P', %w(p P)], ['[{', %w(\[ \{)], [']}', %w(\] \})], ['\|', %w(\\\\ \|)], ], # Caps 〜 RET [ ['Caps'], ['A', %w(a A)], ['S', %w(s S)], ['D', %w(d D)], ['F', %w(f F)], ['G', %w(g G)], ['H', %w(h H)], ['J', %w(j J)], ['K', %w(k K)], ['L', %w(l L)], [';:', %w(; :)], ["'\"", %w(' ")], [''], ['RET', %w(RET)], ], # Shift 〜 Shift [ ['Shift'], ['Z', %w(z Z)], ['X', %w(x X)], ['C', %w(c C)], ['V', %w(v V)], ['B', %w(b B)], ['N', %w(n N)], ['M', %w(m M)], [',<', %w(, <)], ['.>', %w(\. >)], ['/?', %w(\/ \?)], [''], [''], ['Shift'], ], # Ctrl 〜 [right] [ ['Ctrl'], ['Alt'], [''], [''], ['SPC', %w(SPC)], [''], [''], [''], ['Alt'], ['Ctrl'], ['[up]'], ['[down]'], ['[left]'], ['[right]'], ], ] KeyboardJapanese = [ # ESC 〜 DEL [ ['ESC'], ['F1'], ['F2'], ['F3'], ['F4'], ['F5'], ['F6'], ['F7'], ['F8'], ['F9'], ['F10'], ['F11'], ['F12'], ['INS'], ['DEL'], ], # 半角/全角 〜 Backspace [ ['半/全'], ['1!', %w(1 !)], ['2"', %w(2 ")], ['3#', %w(3 #)], ['4$', %w(4 \$)], ['5%', %w(5 %)], ['6&', %w(6 &)], ["7'", %w(7 ')], ['8(', %w(8 \\\()], ['9)', %w(9 \\\))], ['0', %w(0)], ['-=', %w(- =)], ['^~', %w(^ ~)], ['\|', %w(\\\\ \|)], ['BS'], ], # TAB 〜 RET [ ['TAB', %w(TAB)], ['Q', %w(q Q)], ['W', %w(w W)], ['E', %w(e E)], ['R', %w(r R)], ['T', %w(t T)], ['Y', %w(y Y)], ['U', %w(u U)], ['I', %w(i I)], ['O', %w(o O)], ['P', %w(p P)], ['@`', %w(@ `)], ['[{', %w(\[ \{)], [''], ['RET', %w(RET)], ], # Caps 〜 RET [ ['Caps'], ['A', %w(a A)], ['S', %w(s S)], ['D', %w(d D)], ['F', %w(f F)], ['G', %w(g G)], ['H', %w(h H)], ['J', %w(j J)], ['K', %w(k K)], ['L', %w(l L)], [';+', %w(; \+)], [':*', %w(: \*)], [']}', %w(\] \})], [''], [''], # RETのみ特殊で二列で表示する ], # Shift 〜 Shift [ ['Shift'], ['Z', %w(z Z)], ['X', %w(x X)], ['C', %w(c C)], ['V', %w(v V)], ['B', %w(b B)], ['N', %w(n N)], ['M', %w(m M)], [',<', %w(, <)], ['.>', %w(\. >)], ['/?', %w(\/ \?)], ['\_', %w(\\\\ _)], [''], [''], ['Shift'], ], # Ctrl 〜 [right] [ ['Ctrl'], [''], ['Alt'], ['無'], ['SPC', %w(SPC)], ['変'], ['Alt'], ['Ctrl'], ['[up]'], ['[down]'], ['[left]'], ['[right]'], ], ] class EmacsKeybind def initialize(file_name, keyboard, filter) # キーバインドデータ src = [] f = open(ARGV[0]) f.each {|line| src << line.chomp.split(/\t+/) } @keybind = src # キーボードデータ @keyboard = keyboard # フィルター名 @filter = filter end def functions(regexp) funcs = [] @keybind.each do |data| funcs << data if data[0] =~ regexp end funcs end def print_keybind(title, prefix, suffix) puts %Q{<h3>#{title}</h3>} if (@filter == 'html') puts %Q{*** #{title}} if (@filter == 'hatena') puts %Q{<table cellspacing="2" cellpadding="0" border="1">} @keyboard.each do |row| puts %Q{<tr>} row.each do |key| funcs = [] if (key.size == 2) key[1].each do |s| f = functions(Regexp.new("#{prefix}#{s}#{suffix}")) f.each {|a| a[1] += "(#{s.sub(/\\/, '')})" if (a[1] !~ /\(.\)$/) } funcs.concat f end end puts %Q{<td #{td_attr(key, funcs)}><p align="center">#{p_value(key, funcs)}</p></td>} end puts %Q{</tr>} end puts %Q{</table>} end def td_attr(key, funcs) attr = [] attr << 'bgcolor="#80ff00"'if (funcs.size > 0) attr.join(' ') end def p_value(key, funcs) str = "#{key[0]}" funcs.each do |func| str += "<br><b><font size=\"-1\" color=\"#7F00FF\">#{func[1]}</font></b>" end str end def print_standard_keybind print Header if (@filter == 'html') print HeaderHatena if (@filter == 'hatena') print_keybind("C-?", '^C-', '$') print_keybind("M-?", '^M-', '$') print_keybind("C-M-?", '^C-M-', '$') print_keybind("C-x C-?", '^C-x C-', '$') print_keybind("C-x ?", '^C-x ', '$') print_keybind("C-c C-?", '^C-c C-', '$') print_keybind("C-c ?", '^C-c ', '$') print Footer if (@filter == 'html') end end ################################################# # main ################################################# keyboard_kind = nil filter = 'html' opt = OptionParser.new('Usage: emacs_keybind [options] input_file') opt.on('-k', '--keyboard (ascii, japanese)') {|v| keyboard_kind = v } opt.on('-f', '--filter (html, hatena)') {|v| filter = v } opt.parse!(ARGV) case keyboard_kind when 'ascii' keyboard = KeyboardAscii when 'japanese' keyboard = KeyboardJapanese else abort "#{keyboard_kind} is not support. please set keyboard kind(ascci or japanese)" end case filter when 'html' when 'hatena' else abort "#{keyboard_kind} is not support. please set keyboard kind(ascci or japanese)" end keybind = EmacsKeybind.new(ARGV[0], keyboard, filter) keybind.print_standard_keybind
おんがえしのEmacsキーバインド
C-?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 9) | 0 | -= | ^~ | \| | BS |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
M-?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 0 | -= | ^~ | \| | BS | |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
C-M-?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 9) | 0 | -= | ^~ | \| | BS |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
C-x C-?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 9) | 0 | -= | ^~ | \| | BS |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
C-x ?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 0 | -= | ^~ | \| | BS | |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
C-c C-?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 9) | 0 | -= | ^~ | \| | BS |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |
C-c ?
ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | INS | DEL |
半/全 | 1! | 2" | 3# | 4$ | 5% | 6& | 7' | 8( | 9) | 0 | -= | ^~ | \| | BS |
TAB | Q | W | E | R | T | Y | U | I | O | P | @` | [{ | RET | |
Caps | A | S | D | F | G | H | J | K | L | ;+ | :* | ]} | ||
Shift | Z | X | C | V | B | N | M | ,< | .> | /? | \_ | Shift | ||
Ctrl | Alt | 無 | SPC | 変 | Alt | Ctrl | [up] | [down] | [left] | [right] |