readline-ng 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +6 -0
- data/Gemfile.travis +8 -0
- data/README.md +21 -0
- data/Rakefile +9 -0
- data/lib/readline-ng.rb +51 -17
- data/readline-ng.gemspec +2 -0
- data/spec/readline-ng_spec.rb +20 -0
- metadata +46 -6
- data/README +0 -16
data/.travis.yml
ADDED
data/Gemfile.travis
ADDED
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
## Readline ng
|
2
|
+
|
3
|
+
[](http://travis-ci.org/richoH/readline-ng)
|
4
|
+
|
5
|
+
Readline-NG is /not/ a drop in replacement for readline.
|
6
|
+
|
7
|
+
It addresses a very specific need I had inside a twitter client, but
|
8
|
+
hopefully it's of use to someone else, too.
|
9
|
+
|
10
|
+
Readline relies on being able to poll for input often, leading to a
|
11
|
+
hideously inefficient event loop, but generally
|
12
|
+
```ruby
|
13
|
+
reader = ReadlineNG::Reader.new
|
14
|
+
loop do
|
15
|
+
reader.tick
|
16
|
+
reader.each_line do |line|
|
17
|
+
# Handle full line of input
|
18
|
+
reader.puts_above("user input #{line}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
```
|
data/Rakefile
ADDED
data/lib/readline-ng.rb
CHANGED
@@ -2,7 +2,7 @@ module ReadlineNG
|
|
2
2
|
|
3
3
|
VERSION_MAJOR = 0
|
4
4
|
VERSION_MINOR = 0
|
5
|
-
VERSION_PATCH =
|
5
|
+
VERSION_PATCH = 6
|
6
6
|
VERSION = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_PATCH}"
|
7
7
|
|
8
8
|
CONTROL_BS = "\x08"
|
@@ -13,6 +13,9 @@ module ReadlineNG
|
|
13
13
|
KB_BS = "\x7F"
|
14
14
|
KB_CR = "\x0d"
|
15
15
|
|
16
|
+
KB_LEFT = "\x25"
|
17
|
+
KB_RIGHT = "\x27"
|
18
|
+
|
16
19
|
BLANK = " "
|
17
20
|
|
18
21
|
class Reader
|
@@ -23,16 +26,18 @@ module ReadlineNG
|
|
23
26
|
# make a whole lot of sense, although potentially giving out rope is not a
|
24
27
|
# terrible idea here
|
25
28
|
|
26
|
-
attr_accessor :lines, :visible
|
29
|
+
attr_accessor :lines, :visible, :polling_resolution
|
27
30
|
|
28
31
|
# A third party dev can overload filter to implement their own actions
|
29
32
|
def filter
|
30
33
|
end
|
31
34
|
|
32
|
-
def initialize(visible=true)
|
35
|
+
def initialize(visible=true, opts = {})
|
33
36
|
@buf = ""
|
37
|
+
@index = 0
|
34
38
|
@visible = visible
|
35
39
|
@lines = []
|
40
|
+
@polling_resolution = opts[:polling_resolution] || 20
|
36
41
|
if @@initialized
|
37
42
|
STDERR.puts "A ReadlineNG reader is already instanciated, expect weirdness"
|
38
43
|
else
|
@@ -45,6 +50,13 @@ module ReadlineNG
|
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
53
|
+
def wait(n)
|
54
|
+
(n * polling_resolution).times do
|
55
|
+
tick
|
56
|
+
sleep 1.0/polling_resolution
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
def puts_above(string)
|
49
61
|
if visible
|
50
62
|
backspace(@buf.length)
|
@@ -58,14 +70,6 @@ module ReadlineNG
|
|
58
70
|
t = STDIN.read_nonblock(128)
|
59
71
|
t.each_char { |c| process(c) }
|
60
72
|
filter # Expect a 3rd party dev to override this
|
61
|
-
|
62
|
-
raise Interrupt if @buf.include?(CONTROL_INT)
|
63
|
-
|
64
|
-
a = @buf.split("\r")
|
65
|
-
return if a.empty? && @buf.empty?
|
66
|
-
@buf = @buf[-1] == "\r" ? "" : a.pop
|
67
|
-
|
68
|
-
@lines += a
|
69
73
|
rescue Errno::EAGAIN
|
70
74
|
nil
|
71
75
|
end
|
@@ -87,16 +91,48 @@ module ReadlineNG
|
|
87
91
|
private
|
88
92
|
|
89
93
|
def process(c)
|
94
|
+
# TODO This method is getting monolithic, think about how to modularise it
|
90
95
|
case c
|
96
|
+
when "\r"
|
97
|
+
@lines += [@buf]
|
98
|
+
reset
|
99
|
+
when CONTROL_INT
|
100
|
+
raise Interrupt
|
91
101
|
when KB_BS
|
92
|
-
@buf.chop!
|
93
|
-
|
102
|
+
if @buf.chop!
|
103
|
+
@index -= 1
|
104
|
+
backspace
|
105
|
+
end
|
106
|
+
when KB_LEFT
|
107
|
+
if @buf and @index != 0
|
108
|
+
@index -= 1
|
109
|
+
end
|
110
|
+
when KB_RIGHT
|
111
|
+
if @buf and @index < @buf.length
|
112
|
+
@index -= 1
|
113
|
+
end
|
94
114
|
else
|
95
|
-
@buf
|
96
|
-
|
115
|
+
@buf = @buf.insert(@index, c)
|
116
|
+
@index += 1
|
117
|
+
if @index == @buf.length
|
118
|
+
_print c
|
119
|
+
else
|
120
|
+
redraw
|
121
|
+
end
|
97
122
|
end
|
98
123
|
end
|
99
124
|
|
125
|
+
def reset
|
126
|
+
@index, @buf = 0, ""
|
127
|
+
end
|
128
|
+
|
129
|
+
def redraw
|
130
|
+
# TODO We can get away with only going back as far as index, I should
|
131
|
+
# think
|
132
|
+
backspace(@buf.length)
|
133
|
+
_print @buf
|
134
|
+
end
|
135
|
+
|
100
136
|
def backspace(n=1)
|
101
137
|
_print CONTROL_BS*n,BLANK*n,CONTROL_BS*n
|
102
138
|
end
|
@@ -118,8 +154,6 @@ module ReadlineNG
|
|
118
154
|
`stty #{@stty_saved}`
|
119
155
|
end
|
120
156
|
|
121
|
-
|
122
|
-
|
123
157
|
end
|
124
158
|
end
|
125
159
|
|
data/readline-ng.gemspec
CHANGED
@@ -12,6 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = s.summary
|
13
13
|
|
14
14
|
s.add_development_dependency 'rspec'
|
15
|
+
s.add_development_dependency 'mocha'
|
16
|
+
s.add_development_dependency 'rake'
|
15
17
|
|
16
18
|
s.files = `git ls-files`.split("\n")
|
17
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
data/spec/readline-ng_spec.rb
CHANGED
@@ -58,5 +58,25 @@ describe ReadlineNG do
|
|
58
58
|
@reader.get_line.should == "input"
|
59
59
|
end
|
60
60
|
|
61
|
+
it "should respect the left key" do
|
62
|
+
STDIN.stub(:read_nonblock).and_return("asdf", "\x25"*2, "__\r")
|
63
|
+
@reader.get_line.should == "as__df"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not allow the user to left before an empty buffer" do
|
67
|
+
STDIN.stub(:read_nonblock).and_return("\x25"*2, "__", "\x25"*2, "\r")
|
68
|
+
@reader.get_line.should == "__"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should respect the right key" do
|
72
|
+
STDIN.stub(:read_nonblock).and_return("asdf", "\x25"*2, "__", "\x27", "++\r" )
|
73
|
+
@reader.get_line.should == "as_++_df"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not allow the user to right after an empty buffer" do
|
77
|
+
STDIN.stub(:read_nonblock).and_return("\x27"*2, "__", "\x27"*2, "\r")
|
78
|
+
@reader.get_line.should == "__"
|
79
|
+
end
|
80
|
+
|
61
81
|
end
|
62
82
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: readline-ng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,44 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mocha
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
25
62
|
description: Essentially, readline++
|
26
63
|
email:
|
27
64
|
- richo@psych0tik.net
|
@@ -30,8 +67,11 @@ extensions: []
|
|
30
67
|
extra_rdoc_files: []
|
31
68
|
files:
|
32
69
|
- .rvmrc
|
70
|
+
- .travis.yml
|
33
71
|
- Gemfile
|
34
|
-
-
|
72
|
+
- Gemfile.travis
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
35
75
|
- lib/readline-ng.rb
|
36
76
|
- readline-ng.gemspec
|
37
77
|
- spec/readline-ng_spec.rb
|
@@ -55,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
95
|
version: '0'
|
56
96
|
requirements: []
|
57
97
|
rubyforge_project:
|
58
|
-
rubygems_version: 1.8.
|
98
|
+
rubygems_version: 1.8.19
|
59
99
|
signing_key:
|
60
100
|
specification_version: 3
|
61
101
|
summary: Essentially, readline++
|
data/README
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
Readline-NG is /not/ a drop in replacement for readline.
|
2
|
-
|
3
|
-
It addresses a very specific need I had inside a twitter client, but
|
4
|
-
hopefully it's of use to someone else, too.
|
5
|
-
|
6
|
-
Readline relies on being able to poll for input often, leading to a
|
7
|
-
hideously inefficient event loop, but generally
|
8
|
-
|
9
|
-
reader = ReadlineNG::Reader.new
|
10
|
-
loop do
|
11
|
-
reader.tick
|
12
|
-
reader.each_line do |line|
|
13
|
-
# Handle full line of input
|
14
|
-
reader.puts_above("user input #{line}")
|
15
|
-
end
|
16
|
-
end
|