Upload
emasaka
View
842
Download
0
Embed Size (px)
Citation preview
人力@emasaka
#tqrk02
入力@emasaka
#tqrk02
Introduce Myself
自己紹介
Occupation
職業
FREE無職
Period
以上
Main Topic
本題
Termtter
Troubles happens around “Input”
入力まわりはトラブルの巣
And
そして
We hopes to extend “Input” by Ruby
入力をRubyで拡張したい
Example: Prompt the number of characters
例:文字数をプロンプトに表示
※画面は合成です
Example: Auto Complete
例:自動補完
※画面は合成です
For that purpose
そのために
Extend readline by Ruby?
readlineをRubyで拡張?
Have to handle...
●C functions●C variables●C datas
Cの関数、Cの変数、Cのデータを扱わなくちゃならない
Port readline by Ruby?
readlineをRubyに移植?
Many codes
$ cat *.[ch] | wc l28955
大量のコード
Many global variables
$ ruby ne 'next if /\#|\f|\./; print gsub(/\x7f.*/, "")' TAGS | wc l1017
大量のグローバル変数、 static変数
Local static variables
$ grep '^ *static' *.c | wc l39
ローカルのstatic変数も
Strange code
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
へんなコード
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
引数1個が違う関数
Differs one argument
① save global variable
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
グローバル変数を保存
② set argument to global variable
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
引数をグローバル変数にセット
③ call function
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
関数呼び出し
④ restore global variable
intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap;
oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}
グローバル変数を復旧
( ゚д゚)
Make readline-like library by Ruby?
readlineモドキをRubyで新しく作る?
ReadRhine
http://github.com/emasaka/ReadRhine
Works only on Ruby 1.9(for character handling)
Ruby 1.9系専用(文字の扱いが違うので)
Requires (from gem)
●ruby-termios●ruby-terminfo
● “xterm” in terminfo(I found it this morning)
terminfoで“xterm” (今朝気付いた)
How to use
使い方
OOP interface
require 'readrhine'
rr = ReadRhine.new(prompt: '> ')text = rr.readline
OOPインターフェイス
readline compatible interface
require 'readrhine/rlcompat'
text = ReadRhine.readline('> ')
readline互換インターフェイス
Structure
構造
MVC
Buffer
Keymap
History
Undo
Completion
Models Views
Display
Command
Controls
Models don't depend on Views and Controls
ModelはViewやControlに依存していない
Main loop
while true seq = read_key_seq(@keymap) dispatch(seq, @keymap) @display.redisplayend
メインループ
read
eval
unit test friendly
ユニットテストしやすい
Spec of Buffer
it "should contains inserted string at top" do ins_str1 = 'xyz' ins_str2 = '123' @buffer.insert(ins_str1) @buffer.point = 0 @buffer.insert(ins_str2) @buffer.to_s.should == ins_str2 + ins_str1end
BufferのSpec
Spec of Completion
describe ReadRhine::Completion, "when given completion_proc" do before do @list1 = %w[foobar foobaz foohoge] @buffer = ReadRhine::Buffer.new @completion = ReadRhine::Completion.new(@buffer) @completion.completion_proc = >(_){@list1} end
it "should get common string" do @completion.attempted_completion('').should == 'foo' endend
CompletionのSpec
Internal DSL
内部DSL
Key definition
@keymap = Keymap.new@keymap["\Cf"] = :forward_char@keymap["\Cx\Cu"] = :undo
キーの定義
Available commands
いまあるコマンド
Cursor movement
@@default_keymap["\Ca"] = :beginning_of_line@@default_keymap["\Cb"] = :backward_char@@default_keymap["\Ce"] = :end_of_line@@default_keymap["\Cf"] = :forward_char@@default_keymap["\e[D"] = :backward_char@@default_keymap["\e[C"] = :forward_char@@default_keymap["\eOH"] = :beginning_of_line@@default_keymap["\eOF"] = :end_of_line
カーソル移動
Finishing
@@default_keymap["\Cj"] = :done@@default_keymap["\Cm"] = :done
入力終了
Deleting
@@default_keymap["\Cd"] = :delete_char@@default_keymap["\Ch"] = :backward_delete_char@@default_keymap["\Ck"] = :kill_line@@default_keymap["\Cu"] = :unix_line_discard@@default_keymap["\x7f"] = :backward_delete_char
削除
undo
@@default_keymap["\C_"] = :undo@@default_keymap["\Cx\Cu"] = :undo
アンドゥ
Completion
@@default_keymap["\Ci"] = :complete
@@default_keymap["\Ci"] = :menu_complete
補完
History
@@default_keymap["\Cn"] = :next_history@@default_keymap["\Cp"] = :previous_history@@default_keymap["\e[A"] = :previous_history@@default_keymap["\e[B"] = :next_history
履歴
TODOs
やんなくちゃならないこと
● Safe signal handling● More about completion● History search● Per-word cursor movement● Digit argument● ...
Most confusing is ...
いちばんややこしいのは…
character width
文字幅
Width of “☆” is ...
“☆”の幅は…
Only terminal knows
そのターミナルだけが知っている
Messy
めんどくさい
DEMO
デモ