ripl-readline-em 0.1.0 → 0.2.0
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/.gemspec +1 -5
- data/README.rdoc +1 -20
- data/Rakefile +1 -1
- data/examples/readline_callback.rb +14 -0
- data/examples/ripl_readline_em.rb +34 -0
- data/lib/readline/callback.rb +18 -3
- data/lib/ripl/readline/em.rb +6 -72
- data/lib/ripl/readline/eminput.rb +69 -0
- metadata +12 -23
- data/lib/readline_cb.rb +0 -37
data/.gemspec
CHANGED
@@ -12,14 +12,10 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = "A ripl plugin to run readline within eventmachine"
|
13
13
|
s.description = "Run EventMachine code in a ripl shell asynchronously with readline editing and completion"
|
14
14
|
s.required_rubygems_version = ">= 1.3.6"
|
15
|
-
|
16
15
|
s.add_dependency 'ripl', '>= 0.4.2'
|
17
16
|
s.add_dependency 'eventmachine'
|
18
17
|
s.add_dependency 'ffi'
|
19
|
-
|
20
|
-
s.add_development_dependency 'bacon', '>= 1.1.0'
|
21
|
-
|
22
|
-
s.files = Dir.glob(%w[lib/**/*.rb [A-Z]*.{txt,rdoc}]) + %w{Rakefile .gemspec}
|
18
|
+
s.files = Dir.glob(%w[lib/**/*.rb [A-Z]*.{txt,rdoc} examples/**/*.rb]) + %w{Rakefile .gemspec}
|
23
19
|
s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
|
24
20
|
s.license = 'MIT'
|
25
21
|
end
|
data/README.rdoc
CHANGED
@@ -11,24 +11,5 @@ Install the gem with:
|
|
11
11
|
|
12
12
|
== Usage
|
13
13
|
|
14
|
-
|
14
|
+
:include: ./examples/ripl_readline_em.rb
|
15
15
|
|
16
|
-
EventMachine.run do
|
17
|
-
EventMachine.add_periodic_timer(2) do
|
18
|
-
# example writing output while line is being edited
|
19
|
-
puts "#{Time.now}"
|
20
|
-
Readline.refresh_line
|
21
|
-
end
|
22
|
-
|
23
|
-
Ripl.start # exiting ripl shell shuts down EventMachine
|
24
|
-
end
|
25
|
-
|
26
|
-
Writing output to stdout writes over the current input line. A call
|
27
|
-
to Readline.refresh_line fixes things up, but a copy of the prompt and
|
28
|
-
any input text follows along with the line of output. I suspect this
|
29
|
-
isn't the best way...
|
30
|
-
|
31
|
-
== Todo
|
32
|
-
|
33
|
-
Improve technique of being able to write output without messing up the
|
34
|
-
input line.
|
data/Rakefile
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'ripl/readline/em'
|
3
|
+
|
4
|
+
EventMachine.run do
|
5
|
+
EventMachine.add_periodic_timer(2) do
|
6
|
+
# Example of writing output while line is being edited.
|
7
|
+
#
|
8
|
+
# See also http://stackoverflow.com/questions/1512028/gnu-readline-how-do-clear-the-input-line
|
9
|
+
print "\b \b" * Readline.line_buffer.size
|
10
|
+
print "\r"
|
11
|
+
begin
|
12
|
+
puts "#{Time.now}"
|
13
|
+
ensure
|
14
|
+
Readline.forced_update_display
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Start up Ripl, but it will not receive any user input
|
19
|
+
Ripl.start
|
20
|
+
|
21
|
+
# Watch stdin for input, sending it to Ripl as entered (including editing,
|
22
|
+
# history and completion).
|
23
|
+
#
|
24
|
+
# Default behavior is to call EventMachine.stop_event_loop when the shell is
|
25
|
+
# exited. Modify this behavior by passing a hash with an `:on_exit` entry,
|
26
|
+
# either nil or a Proc that will be run on exit instead of the default.
|
27
|
+
EventMachine.watch_stdin Ripl::Readline::EmInput
|
28
|
+
|
29
|
+
# -or-
|
30
|
+
# EventMachine.watch_stdin Ripl::Readline::EmInput, :on_exit => nil
|
31
|
+
|
32
|
+
# Yet another option is to create your own handler module, include
|
33
|
+
# Ripl::Readline::EmInput, and override the `on_exit` method.
|
34
|
+
end
|
data/lib/readline/callback.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ffi'
|
2
|
+
require 'readline'
|
2
3
|
|
3
4
|
module Readline
|
4
5
|
# An alternate, callback-based interface to Readline for use in a
|
@@ -11,7 +12,15 @@ module Readline
|
|
11
12
|
module Callback
|
12
13
|
extend FFI::Library
|
13
14
|
|
14
|
-
|
15
|
+
def self.editline?
|
16
|
+
@__is_editline__ ||= (Readline::VERSION rescue nil).to_s[/editline/i]
|
17
|
+
end
|
18
|
+
|
19
|
+
if editline?
|
20
|
+
ffi_lib 'edit'
|
21
|
+
else
|
22
|
+
ffi_lib 'readline'
|
23
|
+
end
|
15
24
|
|
16
25
|
callback :rl_vcpfunc_t, [:string], :void
|
17
26
|
attach_function :rl_callback_handler_install, [:string, :rl_vcpfunc_t], :void
|
@@ -19,8 +28,15 @@ module Readline
|
|
19
28
|
attach_function :rl_callback_handler_remove, [], :void
|
20
29
|
|
21
30
|
# as-is functions
|
31
|
+
attach_function :forced_update_display, :rl_forced_update_display, [], :void
|
22
32
|
|
23
|
-
|
33
|
+
if editline?
|
34
|
+
def set_prompt(*args)
|
35
|
+
# noop; rl_set_prompt isn't exported by EditLine
|
36
|
+
end
|
37
|
+
else
|
38
|
+
attach_function :set_prompt, :rl_set_prompt, [:string], :int
|
39
|
+
end
|
24
40
|
|
25
41
|
# Set up the terminal for readline I/O and display the initial
|
26
42
|
# expanded value of prompt. Save the value of `block` to call when a
|
@@ -51,7 +67,6 @@ module Readline
|
|
51
67
|
# Readline's use again. EOF is indicated by calling handler with a
|
52
68
|
# NULL line.
|
53
69
|
def callback_read_char
|
54
|
-
$stderr.puts "reading char"
|
55
70
|
rl_callback_read_char
|
56
71
|
end
|
57
72
|
|
data/lib/ripl/readline/em.rb
CHANGED
@@ -2,95 +2,29 @@ require 'eventmachine'
|
|
2
2
|
require 'readline/callback'
|
3
3
|
require 'ripl'
|
4
4
|
require 'ripl/readline'
|
5
|
+
require 'ripl/readline/eminput'
|
5
6
|
|
6
7
|
module Ripl
|
7
8
|
module Readline
|
8
9
|
module Em
|
9
|
-
|
10
|
-
def notify_readable
|
11
|
-
$stderr.puts "is readable"
|
12
|
-
::Readline.callback_read_char
|
13
|
-
$stderr.puts "done"
|
14
|
-
end
|
15
|
-
|
16
|
-
def unbind
|
17
|
-
$stderr.puts "unbind!"
|
18
|
-
::Readline.callback_handler_remove
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module Ripl
|
26
|
-
module Readline
|
27
|
-
module Em
|
28
|
-
VERSION = '0.1.0'
|
10
|
+
VERSION = '0.2.0'
|
29
11
|
|
30
12
|
def get_input
|
31
13
|
history << @input
|
32
14
|
@input
|
33
15
|
end
|
34
16
|
|
35
|
-
def
|
36
|
-
|
37
|
-
::Readline.refresh_line
|
38
|
-
end
|
39
|
-
|
40
|
-
def handle_line(line)
|
41
|
-
catch(:normal_exit) do
|
42
|
-
catch(:ripl_exit) do
|
43
|
-
throw :ripl_exit unless line # line = nil implies EOF
|
44
|
-
|
45
|
-
$stderr.puts "have line #{line}"
|
46
|
-
|
47
|
-
Ripl.shell.input = line
|
48
|
-
Ripl.shell.loop_once
|
49
|
-
redisplay
|
50
|
-
throw :normal_exit
|
51
|
-
end
|
52
|
-
|
53
|
-
# If we got here, it means :ripl_exit was caught
|
54
|
-
::Readline.callback_handler_remove
|
55
|
-
after_loop
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def loop_override
|
60
|
-
before_loop
|
61
|
-
|
62
|
-
::Readline.callback_handler_install do |line|
|
63
|
-
EventMachine.next_tick { handle_line(line) }
|
64
|
-
end
|
65
|
-
|
66
|
-
# is hardcoded $stdin always appropriate?
|
67
|
-
conn = EventMachine.watch $stdin, InputHandler
|
68
|
-
conn.notify_readable = true
|
69
|
-
|
70
|
-
redisplay
|
71
|
-
end
|
72
|
-
|
73
|
-
def before_loop
|
74
|
-
super
|
75
|
-
trap('SIGINT') { handle_interrupt }
|
76
|
-
end
|
77
|
-
|
78
|
-
def after_loop
|
79
|
-
super
|
80
|
-
EventMachine.stop_event_loop
|
81
|
-
end
|
82
|
-
|
83
|
-
def handle_interrupt
|
84
|
-
super
|
85
|
-
redisplay
|
17
|
+
def async_loop
|
18
|
+
# no-op; functionality is done asynchronously
|
86
19
|
end
|
87
20
|
end
|
88
21
|
end
|
89
22
|
end
|
90
23
|
|
91
24
|
Ripl::Shell.include Ripl::Readline::Em
|
25
|
+
|
92
26
|
class Ripl::Shell
|
93
27
|
def loop
|
94
|
-
|
28
|
+
async_loop
|
95
29
|
end
|
96
30
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module EventMachine
|
2
|
+
# Convenience method to add a watch on `STDIN` and set
|
3
|
+
# notify_readable to `true`.
|
4
|
+
#
|
5
|
+
# See EventMachine.watch
|
6
|
+
def self.watch_stdin(handler, *args)
|
7
|
+
conn = EventMachine.watch $stdin, handler, *args
|
8
|
+
conn.notify_readable = true
|
9
|
+
conn
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Ripl
|
14
|
+
module Readline
|
15
|
+
module EmInput
|
16
|
+
def initialize(opts = {})
|
17
|
+
super()
|
18
|
+
@on_exit = opts[:on_exit] || proc { EventMachine.stop_event_loop }
|
19
|
+
handler_install
|
20
|
+
Ripl.shell.before_loop
|
21
|
+
trap('SIGINT') { handle_interrupt }
|
22
|
+
end
|
23
|
+
|
24
|
+
def notify_readable
|
25
|
+
::Readline.callback_read_char
|
26
|
+
end
|
27
|
+
|
28
|
+
def unbind
|
29
|
+
super
|
30
|
+
::Readline.callback_handler_remove
|
31
|
+
Ripl.shell.after_loop
|
32
|
+
on_exit
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_exit
|
36
|
+
@on_exit.call if @on_exit
|
37
|
+
end
|
38
|
+
|
39
|
+
def receive_line(line)
|
40
|
+
catch(:normal_exit) do
|
41
|
+
catch(:ripl_exit) do
|
42
|
+
throw :ripl_exit unless line # line = nil implies EOF
|
43
|
+
|
44
|
+
Ripl.shell.input = line
|
45
|
+
Ripl.shell.loop_once
|
46
|
+
handler_install # EditLine requires handler be
|
47
|
+
# reinstalled for each line.
|
48
|
+
# Seems harmless for Readline
|
49
|
+
throw :normal_exit
|
50
|
+
end
|
51
|
+
detach # :ripl_exit
|
52
|
+
end
|
53
|
+
# :normal_exit
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_interrupt
|
57
|
+
::Readline.callback_handler_remove
|
58
|
+
puts
|
59
|
+
handler_install
|
60
|
+
end
|
61
|
+
|
62
|
+
def handler_install
|
63
|
+
::Readline.callback_handler_install(Ripl.shell.prompt) do |line|
|
64
|
+
EventMachine.next_tick { receive_line(line) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripl-readline-em
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
13
|
-
default_executable:
|
12
|
+
date: 2011-12-02 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: ripl
|
17
|
-
requirement: &
|
16
|
+
requirement: &8372840 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -22,10 +21,10 @@ dependencies:
|
|
22
21
|
version: 0.4.2
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements: *
|
24
|
+
version_requirements: *8372840
|
26
25
|
- !ruby/object:Gem::Dependency
|
27
26
|
name: eventmachine
|
28
|
-
requirement: &
|
27
|
+
requirement: &8372300 !ruby/object:Gem::Requirement
|
29
28
|
none: false
|
30
29
|
requirements:
|
31
30
|
- - ! '>='
|
@@ -33,10 +32,10 @@ dependencies:
|
|
33
32
|
version: '0'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
|
-
version_requirements: *
|
35
|
+
version_requirements: *8372300
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
37
|
name: ffi
|
39
|
-
requirement: &
|
38
|
+
requirement: &8371620 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ! '>='
|
@@ -44,18 +43,7 @@ dependencies:
|
|
44
43
|
version: '0'
|
45
44
|
type: :runtime
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: bacon
|
50
|
-
requirement: &8313560 !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
|
-
requirements:
|
53
|
-
- - ! '>='
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: 1.1.0
|
56
|
-
type: :development
|
57
|
-
prerelease: false
|
58
|
-
version_requirements: *8313560
|
46
|
+
version_requirements: *8371620
|
59
47
|
description: Run EventMachine code in a ripl shell asynchronously with readline editing
|
60
48
|
and completion
|
61
49
|
email: pat@polycrystal.org
|
@@ -66,13 +54,14 @@ extra_rdoc_files:
|
|
66
54
|
- LICENSE.txt
|
67
55
|
files:
|
68
56
|
- lib/ripl/readline/em.rb
|
69
|
-
- lib/
|
57
|
+
- lib/ripl/readline/eminput.rb
|
70
58
|
- lib/readline/callback.rb
|
71
59
|
- LICENSE.txt
|
72
60
|
- README.rdoc
|
61
|
+
- examples/readline_callback.rb
|
62
|
+
- examples/ripl_readline_em.rb
|
73
63
|
- Rakefile
|
74
64
|
- .gemspec
|
75
|
-
has_rdoc: true
|
76
65
|
homepage: http://github.com/pmahoney/ripl-readline-em
|
77
66
|
licenses:
|
78
67
|
- MIT
|
@@ -94,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
83
|
version: 1.3.6
|
95
84
|
requirements: []
|
96
85
|
rubyforge_project:
|
97
|
-
rubygems_version: 1.
|
86
|
+
rubygems_version: 1.8.10
|
98
87
|
signing_key:
|
99
88
|
specification_version: 3
|
100
89
|
summary: A ripl plugin to run readline within eventmachine
|
data/lib/readline_cb.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'readline/alt'
|
2
|
-
|
3
|
-
module Readline::Alt::Demo
|
4
|
-
class << self
|
5
|
-
# Demonstration method to read a line of input using the callback
|
6
|
-
# functions rather than a direct call to Readline#readline.
|
7
|
-
def readline(prompt = nil)
|
8
|
-
readline_string = nil
|
9
|
-
|
10
|
-
Readline.handler_install(prompt) do |str|
|
11
|
-
readline_string = str
|
12
|
-
end
|
13
|
-
|
14
|
-
begin
|
15
|
-
Readline.read_char until readline_string
|
16
|
-
ensure
|
17
|
-
Readline.handler_remove
|
18
|
-
end
|
19
|
-
|
20
|
-
readline_string
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
#line = Readline::Alt::Demo.readline('> ')
|
26
|
-
#puts "READ A LINE::: #{line.inspect}"
|
27
|
-
|
28
|
-
require 'ripl/readline/em'
|
29
|
-
|
30
|
-
EventMachine.run do
|
31
|
-
EventMachine.add_periodic_timer(2) do
|
32
|
-
puts "#{Time.now} alive!"
|
33
|
-
Readline.refresh_line
|
34
|
-
end
|
35
|
-
|
36
|
-
Ripl.start
|
37
|
-
end
|