SlideShare a Scribd company logo
人力
     @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 ­l
28955




        大量のコード
Many global variables
$ ruby ­ne 'next if /#|f|./; 
print gsub(/x7f.*/, "")' TAGS | 
wc ­l
1017




     大量のグローバル変数、
     static変数
Local static variables
$ grep '^  *static' *.c | wc ­l
39




    ローカルのstatic変数も
Strange code
int
rl_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);
}


            へんなコード
int
rl_bind_key_in_map (key, function, map)
     int key;
     rl_command_func_t *function;
     Keymap map;
{
  int result;
  Keymap oldmap;
                                     Differs one
                                     argument
  oldmap = _rl_keymap;
  _rl_keymap = map;
  result = rl_bind_key (key, function);
  _rl_keymap = oldmap;
  return (result);
}


            引数1個が違う関数
① save global variable
int
rl_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
int
rl_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
int
rl_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
int
rl_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
Models             Views
                   Display
Buffer
Keymap
History            Controls
Undo               Command
Completion
Models don't depend on
  Views and Controls

    ModelはViewやControlに
    依存していない
Main loop
                             read
while true
  seq = read_key_seq(@keymap)
  dispatch(seq, @keymap)     eval
  @display.redisplay
end                       print



         メインループ
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_str1
end



            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'
  end
end

                 CompletionのSpec
Internal DSL

 内部DSL
Key definition
@keymap = Keymap.new
@keymap["C­f"] = :forward_char
@keymap["C­xC­u"] = :undo




            キーの定義
Available commands

  いまあるコマンド
Cursor movement
@@default_keymap["C­a"] = :beginning_of_line
@@default_keymap["C­b"] = :backward_char
@@default_keymap["C­e"] = :end_of_line
@@default_keymap["C­f"] = :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["C­j"] = :done
@@default_keymap["C­m"] = :done




            入力終了
Deleting
@@default_keymap["C­d"] = :delete_char
@@default_keymap["C­h"] = :backward_delete_char
@@default_keymap["C­k"] = :kill_line
@@default_keymap["C­u"] = :unix_line_discard
@@default_keymap["x7f"] = :backward_delete_char




             削除
undo
@@default_keymap["C­_"] = :undo
@@default_keymap["C­xC­u"] = :undo




            アンドゥ
Completion
@@default_keymap["C­i"] = :complete

@@default_keymap["C­i"] = :menu_complete




            補完
History
@@default_keymap["C­n"] = :next_history
@@default_keymap["C­p"] = :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

デモ

More Related Content

人力