rawline 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,130 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # history_buffer.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+ #
12
+ #
13
+ module RawLine
14
+
15
+ #
16
+ # The HistoryBuffer class is used to hold the editor and line histories, as well
17
+ # as word completion matches.
18
+ #
19
+ class HistoryBuffer < Array
20
+
21
+ attr_reader :position, :size
22
+ attr_accessor :duplicates, :exclude, :cycle
23
+
24
+ undef <<
25
+
26
+ #
27
+ # Create an instance of RawLine::HistoryBuffer.
28
+ # This method takes an optional block used to override the
29
+ # following instance attributes:
30
+ # * <tt>@duplicates</tt> - whether or not duplicate items will be stored in the
31
+ # buffer.
32
+ # * <tt>@exclude</tt> - a Proc object defining exclusion rules to prevent items
33
+ # from being added to the buffer.
34
+ # * <tt>@cycle</tt> - Whether or not the buffer is cyclic.
35
+ #
36
+ def initialize(size)
37
+ @duplicates = true
38
+ @exclude = lambda { nil }
39
+ @cycle = false
40
+ yield self if block_given?
41
+ @size = size
42
+ @position = nil
43
+ end
44
+
45
+ #
46
+ # Resize the buffer, resetting <tt>@position</tt> to nil.
47
+ #
48
+ def resize(new_size)
49
+ if new_size < @size
50
+ @size-new_size.times { pop }
51
+ end
52
+ @size = new_size
53
+ @position = nil
54
+ end
55
+
56
+ #
57
+ # Clear the content of the buffer and reset <tt>@position</tt> to nil.
58
+ #
59
+ def empty
60
+ @position = nil
61
+ clear
62
+ end
63
+
64
+ #
65
+ # Retrieve the element at <tt>@position</tt>.
66
+ #
67
+ def get
68
+ return nil unless length > 0
69
+ @position = length-1 unless @position
70
+ at @position
71
+ end
72
+
73
+ #
74
+ # Return true if <tt>@position</tt> is at the end of the buffer.
75
+ #
76
+ def end?
77
+ @position == length-1
78
+ end
79
+
80
+ #
81
+ # Return true if <tt>@position</tt> is at the start of the buffer.
82
+ #
83
+ def start?
84
+ @position == 0
85
+ end
86
+
87
+ #
88
+ # Decrement <tt>@position</tt>.
89
+ #
90
+ def back
91
+ return nil unless length > 0
92
+ case @position
93
+ when nil: @position = length-1
94
+ when 0: @position = length-1 if @cycle
95
+ else @position -= 1
96
+ end
97
+ end
98
+
99
+ #
100
+ # Increment <tt>@position</tt>.
101
+ #
102
+ def forward
103
+ return nil unless length > 0
104
+ case @position
105
+ when nil: @position = length-1
106
+ when length-1: @position = 0 if @cycle
107
+ else @position += 1
108
+ end
109
+ end
110
+
111
+ #
112
+ # Add a new item to the buffer.
113
+ #
114
+ def <<(item)
115
+ delete(item) unless @duplicates
116
+ unless @exclude.call(item)
117
+ # Remove the oldest element if size is exceeded
118
+ if @size <= length
119
+ reverse!.pop
120
+ reverse!
121
+ end
122
+ # Add the new item and reset the position
123
+ push(item)
124
+ @position = nil
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,158 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # line.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+
12
+ module RawLine
13
+
14
+ #
15
+ # The Line class is used to represent the current line being processed and edited
16
+ # by RawLine::Editor. It keeps track of the characters typed, the cursor position,
17
+ # the current word and maintains an internal history to allow undos and redos.
18
+ #
19
+ class Line
20
+
21
+ attr_accessor :text, :position, :history, :prompt, :history_size, :word_separator
22
+ attr_reader :offset
23
+
24
+ include HighLine::SystemExtensions
25
+
26
+ #
27
+ # Create an instance of RawLine::Line.
28
+ # This method takes an optional block used to override the
29
+ # following instance attributes:
30
+ # * <tt>@text</tt> - the line text.
31
+ # * <tt>@history_size</tt> - the size of the line history buffer.
32
+ # * <tt>@position</tt> - the current cursor position within the line.
33
+ # * <tt>@prompt</tt> - a prompt to prepend to the line text.
34
+ #
35
+ def initialize(history_size)
36
+ @text = ""
37
+ @history_size = history_size
38
+ @position = 0
39
+ @prompt = ""
40
+ @word_separator = ' '
41
+ yield self if block_given?
42
+ @words = []
43
+ @history = RawLine::HistoryBuffer.new(@history_size)
44
+ @history << "" # Add empty line for complete undo...
45
+ @offset = @prompt.length
46
+ end
47
+
48
+ #
49
+ # Return the maximum line length. By default, it corresponds to the terminal's
50
+ # width minus the length of the line prompt.
51
+ #
52
+ def max_length
53
+ terminal_size[0]-@offset
54
+ end
55
+
56
+ #
57
+ # Return information about the current word, as a Hash composed by the following
58
+ # elements:
59
+ # * <tt>:start</tt>: The position in the line corresponding to the word start
60
+ # * <tt>:end</tt>: The position in the line corresponding to the word end
61
+ # * <tt>:text</tt>: The word text.
62
+ def word
63
+ last = @text.index(@word_separator, @position)
64
+ first = @text.rindex(@word_separator, @position)
65
+ # Trim word separators and handle EOL and BOL
66
+ if first: first +=1
67
+ else first = bol
68
+ end
69
+ if last: last -=1
70
+ else last = eol+1 unless last
71
+ end
72
+ # Swap if overlapping
73
+ last, first = first, last if last < first
74
+ text = @text[first..last]
75
+ # Repeat the search if within word separator
76
+ if text.match @word_separator then
77
+ last = first
78
+ first = @text.rindex(@word_separator, first)
79
+ if first then first+=1
80
+ else first = bol
81
+ end
82
+ text = @text[first..last]
83
+ end
84
+ {:start => first, :end => last, :text => text}
85
+ end
86
+
87
+ #
88
+ # Return the position corresponding to the beginning of the line.
89
+ #
90
+ def bol
91
+ 0
92
+ end
93
+
94
+ #
95
+ # Return true if the cursor is at the beginning of the line.
96
+ #
97
+ def bol?
98
+ @position<=bol
99
+ end
100
+
101
+ #
102
+ # Return the position corresponding to the end of the line.
103
+ #
104
+ def eol
105
+ @text.length-1
106
+ end
107
+
108
+ #
109
+ # Return true if the cursor is at the end of the line.
110
+ #
111
+ def eol?
112
+ @position>=eol
113
+ end
114
+
115
+ #
116
+ # Decrement the line position by <tt>offset</tt>
117
+ #
118
+ def left(offset=1)
119
+ @position = (@position-offset <= 0) ? 0 : @position-offset
120
+ end
121
+
122
+ #
123
+ # Increment the line position by <tt>offset</tt>
124
+ #
125
+ def right(offset=1)
126
+ @position = (@position+offset >= max_length) ? max_length : @position+offset
127
+ end
128
+
129
+ #
130
+ # Add a character (expressed as a character code) to the line text.
131
+ #
132
+ def <<(char)
133
+ @text << char.chr
134
+ end
135
+
136
+ #
137
+ # Access the line text at <tt>@index</tt>
138
+ #
139
+ def [](index)
140
+ @text[index]
141
+ end
142
+
143
+ #
144
+ # Modify the character(s) in the line text at <tt>@index</tt>
145
+ #
146
+ def []=(index, chars)
147
+ @text[index] = chars
148
+ end
149
+
150
+ #
151
+ # Return the length of the line text.
152
+ #
153
+ def length
154
+ @text.length
155
+ end
156
+
157
+ end
158
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # vt220_terminal.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+
12
+ module RawLine
13
+
14
+ #
15
+ # This class is used to define all the most common character codes and
16
+ # escape sequences used on *nix systems.
17
+ #
18
+ class VT220Terminal < Terminal
19
+
20
+ def initialize
21
+ super
22
+ @escape_codes = [?\e]
23
+ @keys.merge!(
24
+ {
25
+ :up_arrow => [?\e, ?[, ?A],
26
+ :down_arrow => [?\e, ?[, ?B],
27
+ :right_arrow => [?\e, ?[, ?C],
28
+ :left_arrow => [?\e, ?[, ?D],
29
+ :insert => [?\e, ?[, ?2, ?~],
30
+ :delete => [?\e, ?[, ?3, ?~],
31
+ :backspace => [?\C-?],
32
+ :enter => [?\n],
33
+
34
+ :ctrl_alt_a => [?\e, ?\C-a],
35
+ :ctrl_alt_b => [?\e, ?\C-b],
36
+ :ctrl_alt_c => [?\e, ?\C-c],
37
+ :ctrl_alt_d => [?\e, ?\C-d],
38
+ :ctrl_alt_e => [?\e, ?\C-e],
39
+ :ctrl_alt_f => [?\e, ?\C-f],
40
+ :ctrl_alt_g => [?\e, ?\C-g],
41
+ :ctrl_alt_h => [?\e, ?\C-h],
42
+ :ctrl_alt_i => [?\e, ?\C-i],
43
+ :ctrl_alt_j => [?\e, ?\C-j],
44
+ :ctrl_alt_k => [?\e, ?\C-k],
45
+ :ctrl_alt_l => [?\e, ?\C-l],
46
+ :ctrl_alt_m => [?\e, ?\C-m],
47
+ :ctrl_alt_n => [?\e, ?\C-n],
48
+ :ctrl_alt_o => [?\e, ?\C-o],
49
+ :ctrl_alt_p => [?\e, ?\C-p],
50
+ :ctrl_alt_q => [?\e, ?\C-q],
51
+ :ctrl_alt_r => [?\e, ?\C-r],
52
+ :ctrl_alt_s => [?\e, ?\C-s],
53
+ :ctrl_alt_t => [?\e, ?\C-t],
54
+ :ctrl_alt_u => [?\e, ?\C-u],
55
+ :ctrl_alt_v => [?\e, ?\C-v],
56
+ :ctrl_alt_w => [?\e, ?\C-w],
57
+ :ctrl_alt_x => [?\e, ?\C-x],
58
+ :ctrl_alt_y => [?\e, ?\C-y],
59
+ :ctrl_alt_z => [?\e, ?\C-z]
60
+ })
61
+ end
62
+
63
+ end
64
+
65
+
66
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # windows_terminal.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+
12
+ module RawLine
13
+
14
+ #
15
+ # This class is used to define all the most common character codes and
16
+ # escape sequences used on Windows systems.
17
+ #
18
+ class WindowsTerminal < Terminal
19
+
20
+ def initialize
21
+ super
22
+ @escape_codes = [0, 27, 224]
23
+ @keys.merge!(
24
+ {
25
+ :left_arrow => [224, 75],
26
+ :right_arrow => [224, 77],
27
+ :up_arrow => [224, 72],
28
+ :down_arrow => [224, 80],
29
+ :insert => [224, 82],
30
+ :delete => [224, 83],
31
+ :backspace => [8],
32
+ :enter => [13],
33
+
34
+ :ctrl_alt_a => [0, 30],
35
+ :ctrl_alt_b => [0, 48],
36
+ :ctrl_alt_c => [0, 46],
37
+ :ctrl_alt_d => [0, 32],
38
+ :ctrl_alt_e => [0, 63],
39
+ :ctrl_alt_f => [0, 33],
40
+ :ctrl_alt_g => [0, 34],
41
+ :ctrl_alt_h => [0, 35],
42
+ :ctrl_alt_i => [0, 23],
43
+ :ctrl_alt_j => [0, 36],
44
+ :ctrl_alt_k => [0, 37],
45
+ :ctrl_alt_l => [0, 26],
46
+ :ctrl_alt_m => [0, 32],
47
+ :ctrl_alt_n => [0, 31],
48
+ :ctrl_alt_o => [0, 24],
49
+ :ctrl_alt_p => [0, 25],
50
+ :ctrl_alt_q => [0, 16],
51
+ :ctrl_alt_r => [0, 19],
52
+ :ctrl_alt_s => [0, 31],
53
+ :ctrl_alt_t => [0, 20],
54
+ :ctrl_alt_u => [0, 22],
55
+ :ctrl_alt_v => [0, 47],
56
+ :ctrl_alt_w => [0, 17],
57
+ :ctrl_alt_x => [0, 45],
58
+ :ctrl_alt_y => [0, 21],
59
+ :ctrl_alt_z => [0, 44]
60
+ })
61
+ end
62
+
63
+ end
64
+
65
+
66
+ end
@@ -0,0 +1,87 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # terminal.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+ #
12
+ #
13
+ module RawLine
14
+
15
+ #
16
+ # The Terminal class defines character codes and code sequences which can be
17
+ # bound to actions by editors.
18
+ # An OS-dependent subclass of RawLine::Terminal is automatically instantiated by
19
+ # RawLine::Editor.
20
+ #
21
+ class Terminal
22
+
23
+ include HighLine::SystemExtensions
24
+
25
+ attr_accessor :escape_codes
26
+ attr_reader :keys, :escape_sequences
27
+
28
+ #
29
+ # Create an instance of RawLine::Terminal.
30
+ #
31
+ def initialize
32
+ @keys =
33
+ {
34
+ :tab => [?\t],
35
+ :return => [?\r],
36
+ :newline => [?\n],
37
+ :escape => [?\e],
38
+
39
+ :ctrl_a => [?\C-a],
40
+ :ctrl_b => [?\C-b],
41
+ :ctrl_c => [?\C-c],
42
+ :ctrl_d => [?\C-d],
43
+ :ctrl_e => [?\C-e],
44
+ :ctrl_f => [?\C-f],
45
+ :ctrl_g => [?\C-g],
46
+ :ctrl_h => [?\C-h],
47
+ :ctrl_i => [?\C-i],
48
+ :ctrl_j => [?\C-j],
49
+ :ctrl_k => [?\C-k],
50
+ :ctrl_l => [?\C-l],
51
+ :ctrl_m => [?\C-m],
52
+ :ctrl_n => [?\C-n],
53
+ :ctrl_o => [?\C-o],
54
+ :ctrl_p => [?\C-p],
55
+ :ctrl_q => [?\C-q],
56
+ :ctrl_r => [?\C-r],
57
+ :ctrl_s => [?\C-s],
58
+ :ctrl_t => [?\C-t],
59
+ :ctrl_u => [?\C-u],
60
+ :ctrl_v => [?\C-v],
61
+ :ctrl_w => [?\C-w],
62
+ :ctrl_x => [?\C-x],
63
+ :ctrl_y => [?\C-y],
64
+ :ctrl_z => [?\C-z]
65
+ }
66
+ @escape_codes = []
67
+ @escape_sequences = []
68
+ update
69
+ end
70
+
71
+ #
72
+ # Update the terminal escape sequences. This method is called automatically
73
+ # by RawLine::Editor#bind().
74
+ #
75
+ def update
76
+ @keys.each_value do |k|
77
+ l = k.length
78
+ if l > 1 then
79
+ @escape_sequences << k unless @escape_sequences.include? k
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+
87
+ end
data/lib/rawline.rb ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ #
4
+ # RawLine.rb
5
+ #
6
+ # Created by Fabio Cevasco on 2008-03-01.
7
+ # Copyright (c) 2008 Fabio Cevasco. All rights reserved.
8
+ #
9
+ # This is Free Software. See LICENSE for details.
10
+ #
11
+
12
+ module RawLine
13
+ HOME = File.dirname(File.expand_path(__FILE__))
14
+ class BindingException < Exception; end
15
+ begin
16
+ WIN32CONSOLE = require "win32console" if PLATFORM.match(/win32/i)
17
+ ANSI = true
18
+ rescue
19
+ ANSI = false
20
+ end
21
+ end
22
+
23
+ require "rubygems"
24
+ require "highline"
25
+ require "#{RawLine::HOME}/RawLine/terminal"
26
+ require "#{RawLine::HOME}/RawLine/terminal/windows_terminal"
27
+ require "#{RawLine::HOME}/RawLine/terminal/vt220_terminal"
28
+ require "#{RawLine::HOME}/RawLine/history_buffer"
29
+ require "#{RawLine::HOME}/RawLine/line"
30
+ require "#{RawLine::HOME}/RawLine/editor"
31
+
32
+
data/test/test_all.rb ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ module RawLine
4
+ TEST_HOME = File.dirname(File.expand_path(__FILE__))+'/..' unless const_defined?(:TEST_HOME)
5
+ end
6
+
7
+ require "test_history_buffer"
8
+ require "test_line"
9
+ require "test_editor"
@@ -0,0 +1,169 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ module RawLine
4
+ TEST_HOME = File.dirname(File.expand_path(__FILE__))+'/..' unless const_defined?(:TEST_HOME)
5
+ end
6
+
7
+ require 'highline/system_extensions'
8
+
9
+ module HighLine::SystemExtensions
10
+ # Override Windows' character reading so it's not tied to STDIN.
11
+ def get_character( input = STDIN )
12
+ input.getc
13
+ end
14
+ end
15
+
16
+ require 'stringio'
17
+ require "#{RawLine::TEST_HOME}/lib/RawLine"
18
+
19
+ describe RawLine::Editor do
20
+
21
+ before :each do
22
+ @output = StringIO.new
23
+ @input = StringIO.new
24
+ @editor = RawLine::Editor.new(@input, @output)
25
+ end
26
+
27
+ it "reads raw characters from @input" do
28
+ @input << "test #1"
29
+ @input.rewind
30
+ @editor.read
31
+ @editor.line.text.should == "test #1"
32
+ @output.string.should == "test #1"
33
+ end
34
+
35
+ it "can bind keys to code blocks" do
36
+ @editor.bind(:ctrl_w) { @editor.write "test #2a" }
37
+ @editor.bind(?\C-q) { "test #2b" }
38
+ @editor.bind(21) { "test #2c" }
39
+ @editor.bind([22]) { "test #2d" }
40
+ @editor.terminal.escape_codes = [] # remove any existing escape codes
41
+ lambda {@editor.bind({:test => [?\e, ?t, ?e, ?s, ?t]}) { "test #2e" }}.should raise_error(RawLine::BindingException)
42
+ @editor.terminal.escape_codes << ?\e
43
+ lambda {@editor.bind({:test => "\etest"}) { "test #2e" }}.should_not raise_error(RawLine::BindingException)
44
+ lambda {@editor.bind("\etest2") { "test #2f" }}.should_not raise_error(RawLine::BindingException)
45
+ @input << ?\C-w.chr
46
+ @input.rewind
47
+ @editor.read
48
+ @editor.line.text.should == "test #2a"
49
+ @editor.char = [?\C-q]
50
+ @editor.press_key.should == "test #2b"
51
+ @editor.char = [?\C-u]
52
+ @editor.press_key.should == "test #2c"
53
+ @editor.char = [?\C-v]
54
+ @editor.press_key.should == "test #2d"
55
+ @editor.char = [?\e, ?t, ?e, ?s, ?t]
56
+ @editor.press_key.should == "test #2e"
57
+ @editor.char = [?\e, ?t, ?e, ?s, ?t, ?2]
58
+ @editor.press_key.should == "test #2f"
59
+ end
60
+
61
+ it "keeps track of the cursor position" do
62
+ @input << "test #4"
63
+ @input.rewind
64
+ @editor.read
65
+ @editor.line.position.should == 7
66
+ 3.times { @editor.move_left }
67
+ @editor.line.position.should == 4
68
+ 2.times { @editor.move_right }
69
+ @editor.line.position.should == 6
70
+ end
71
+
72
+ it "can delete characters" do
73
+ @input << "test #5"
74
+ @input.rewind
75
+ @editor.read
76
+ 3.times { @editor.move_left }
77
+ 4.times { @editor.delete_left_character }
78
+ 3.times { @editor.delete_character }
79
+ @editor.line.text.should == ""
80
+ @editor.line.position.should == 0
81
+ end
82
+
83
+ it "can clear the whole line" do
84
+ @input << "test #5"
85
+ @input.rewind
86
+ @editor.read
87
+ @editor.clear_line
88
+ @editor.line.text.should == ""
89
+ @editor.line.position.should == 0
90
+ end
91
+
92
+ it "supports undo and redo" do
93
+ @input << "test #6"
94
+ @input.rewind
95
+ @editor.read
96
+ 3.times { @editor.delete_left_character }
97
+ 2.times { @editor.undo }
98
+ @editor.line.text.should == "test #"
99
+ 2.times { @editor.redo }
100
+ @editor.line.text.should == "test"
101
+ end
102
+
103
+ it "supports history" do
104
+ @input << "test #7a"
105
+ @input.rewind
106
+ @editor.read
107
+ @editor.newline
108
+ @input << "test #7b"
109
+ @input.pos = 8
110
+ @editor.read
111
+ @editor.newline
112
+ @input << "test #7c"
113
+ @input.pos = 16
114
+ @editor.read
115
+ @editor.newline
116
+ @input << "test #7d"
117
+ @input.pos = 24
118
+ @editor.read
119
+ @editor.newline
120
+ @editor.history_back
121
+ @editor.line.text.should == "test #7c"
122
+ 10.times { @editor.history_back }
123
+ @editor.line.text.should == "test #7a"
124
+ 2.times { @editor.history_forward }
125
+ @editor.line.text.should == "test #7c"
126
+ end
127
+
128
+ it "can overwrite lines" do
129
+ @input << "test #8a"
130
+ @input.rewind
131
+ @editor.read
132
+ @editor.overwrite_line("test #8b", 2)
133
+ @editor.line.text.should == "test #8b"
134
+ @editor.line.position.should == 2
135
+ end
136
+
137
+ it "can complete words" do
138
+ @editor.completion_append_string = "\t"
139
+ @editor.bind(:tab) { @editor.complete }
140
+ @editor.completion_proc = lambda do |word|
141
+ if word
142
+ ['select', 'update', 'delete', 'debug', 'destroy'].find_all { |e| e.match(/^#{Regexp.escape(word)}/) }
143
+ end
144
+ end
145
+ @input << "test #9 de" << ?\t.chr << ?\t.chr
146
+ @input.rewind
147
+ @editor.read
148
+ @editor.line.text.should == "test #9 delete\t"
149
+ end
150
+
151
+ it "supports INSERT and REPLACE modes" do
152
+ @input << "test 0"
153
+ @editor.terminal.keys[:left_arrow].each { |k| @input << k.chr }
154
+ @input << "#1"
155
+ @input.rewind
156
+ @editor.read
157
+ @editor.line.text.should == "test #10"
158
+ @editor.toggle_mode
159
+ @input << "test 0"
160
+ @editor.terminal.keys[:left_arrow].each { |k| @input << k.chr }
161
+ @input << "#1"
162
+ @input.pos = 10
163
+ @editor.read
164
+ @editor.line.text.should == "test #1"
165
+ end
166
+
167
+
168
+ end
169
+