terminal_rb 0.17.0 → 0.17.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a91661bad1d2b3b3d432dd5ae4e0e0101b3a006773d30c58a39a75c703ab03e
4
- data.tar.gz: 533349101fb9890e0bf0e73a407f9302ac881eeb9376aca78aba1e76486544ad
3
+ metadata.gz: 3ccb3312146fca100bd13e4c079e5cf6f4a33e73ef9eb526765df1309ae5168e
4
+ data.tar.gz: ce4f5679183067ac7f7d84196db0ad9a06a22878fda79ec302fbacc8047699fa
5
5
  SHA512:
6
- metadata.gz: 39c6527ea4d97ff28e1fc11408297057ee537b44c945be71814cc7b99b4e2759863c063b023d1c7d9d4bb4b9c0ae8172bbb3ceb9166c93b54301119fb0443e9d
7
- data.tar.gz: f068bf0ffbc3952260cae2a5e56506063b5bc566c66b4cac8f138732a1bd748a17c9d165ffa29a22a4ca85a12e4c78ba88d3e722a349c0de70d899892f5c7e06
6
+ metadata.gz: 8a898bce2dc22f5b1d873ace6cef5ea53046318d68bc80062898ec7be43553acde5a7709c1b1043666533e91fbecec3e66dd0372c0adb1642803b4273f0c91d0
7
+ data.tar.gz: d9a06bd5ef76f97a0331bb2e05681fae5103dbe69a21c8e5ac0b97cb7342a6569d0e595b90b00744f22ed9253fc858fdbcd8e81e37ce595bfd1bb830c5cea2b9
@@ -49,14 +49,16 @@ module Terminal
49
49
  # @return [KeyEvent] next event
50
50
  # @return [nil] in error case
51
51
  def read_key_event
52
- case input_mode
53
- when :dumb
54
- raw = read_dumb or return
55
- opts = @dumb_keys[raw.ord] if raw.size == 1
56
- KeyEvent.new(raw, *opts)
57
- when :csi_u, :legacy
58
- raw = read_tty or return
59
- KeyEvent[raw]
52
+ prevent_input_recursion do
53
+ case input_mode
54
+ when :dumb
55
+ raw = read_dumb or return
56
+ opts = @dumb_keys[raw.ord] if raw.size == 1
57
+ KeyEvent.new(raw, *opts)
58
+ when :csi_u, :legacy
59
+ raw = read_tty or return
60
+ KeyEvent[raw]
61
+ end
60
62
  end
61
63
  end
62
64
 
@@ -80,20 +82,33 @@ module Terminal
80
82
  # when no block was given
81
83
  def on_key_event(mouse: false, mouse_move: false, focus: false, &block)
82
84
  return unless block
83
- case input_mode
84
- when :dumb
85
- on_bumb_key_event(&block)
86
- true
87
- when :csi_u, :legacy
88
- on_tty_key_event(mouse_option(mouse, mouse_move, focus), &block)
89
- true
90
- else
91
- false
85
+ prevent_input_recursion do
86
+ case input_mode
87
+ when :dumb
88
+ on_bumb_key_event(&block)
89
+ true
90
+ when :csi_u, :legacy
91
+ on_tty_key_event(mouse_option(mouse, mouse_move, focus), &block)
92
+ true
93
+ else
94
+ false
95
+ end
92
96
  end
93
97
  end
94
98
 
95
99
  private
96
100
 
101
+ def prevent_input_recursion
102
+ if (@key_event += 1) != 1
103
+ raise(RuntimeError, 'already reading key events', caller(2))
104
+ end
105
+ begin
106
+ yield
107
+ ensure
108
+ @key_event -= 1
109
+ end
110
+ end
111
+
97
112
  def mouse_option(mouse, mouse_move, focus)
98
113
  opts = +(mouse ? '1000' : '')
99
114
  # highlight: '1001'
@@ -189,5 +204,7 @@ module Terminal
189
204
  0x1b => :Esc
190
205
  }.compare_by_identity.freeze
191
206
 
207
+ @key_event = 0
208
+
192
209
  autoload :KeyEvent, "#{__dir__}/input/key_event.rb"
193
210
  end
@@ -5,50 +5,43 @@ module Terminal
5
5
  class << self
6
6
  def exec(cmd, env: {}, shell: false, input: nil, **options)
7
7
  options = options.except(:in, :out, :err)
8
- if shell
9
- cmd = cmd.map! { _escape(_1) }.join(' ')
10
- elsif cmd.size == 1 && cmd[0].include?(' ')
11
- cmd = cmd[0]
12
- end
8
+ cmd = cmd.map! { _escape(_1) }.join(' ') if shell
9
+ input = Input[input]
10
+ thread = nil
13
11
 
14
- input = Input.for(input)
15
- ret = nil
16
12
  with_io(options, input) do |cio, out_r, err_r, in_w|
17
13
  thread = Process.detach(Process.spawn(env, *cmd, options))
18
- begin
19
- cio.each(&:close)
20
- read = [out_r, err_r]
21
- write = [in_w] if in_w
22
- while !read.empty? || write
23
- rr, wr, = IO.select(read, write)
24
- if rr.include?(out_r)
25
- begin
26
- yield(out_r.readline(chomp: true), :output)
27
- rescue SystemCallError, IOError
28
- read.delete(out_r)
29
- end
30
- end
31
- if rr.include?(err_r)
32
- begin
33
- yield(err_r.readline(chomp: true), :error)
34
- rescue SystemCallError, IOError
35
- read.delete(err_r)
36
- end
14
+ cio.each(&:close)
15
+ read = [out_r, err_r]
16
+ write = [in_w] if in_w
17
+ until read.empty? && write.nil?
18
+ rr, wr, = IO.select(read, write)
19
+ if rr.include?(out_r)
20
+ begin
21
+ yield(out_r.readline(chomp: true), :output)
22
+ rescue SystemCallError, IOError
23
+ read.delete(out_r)
37
24
  end
38
- next if wr.empty?
25
+ end
26
+ if rr.include?(err_r)
39
27
  begin
40
- next if input.call(in_w)
41
- in_w.close
42
- write = nil
28
+ yield(err_r.readline(chomp: true), :error)
43
29
  rescue SystemCallError, IOError
44
- write = nil
30
+ read.delete(err_r)
45
31
  end
46
32
  end
47
- ensure
48
- ret = thread.join.value
33
+ next if wr.empty?
34
+ begin
35
+ next if input.call(in_w)
36
+ in_w.close
37
+ write = nil
38
+ rescue SystemCallError, IOError
39
+ write = nil
40
+ end
49
41
  end
50
42
  end
51
- ret
43
+
44
+ thread.join.value if thread
52
45
  rescue SystemCallError, IOError
53
46
  nil
54
47
  end
@@ -70,58 +63,46 @@ module Terminal
70
63
  end
71
64
 
72
65
  def _escape(str)
73
- return +"''" if str.empty?
74
- str = str.dup
75
- str.gsub!(%r{[^A-Za-z0-9_\-.,:+/@\n]}, "\\\\\\&")
76
- str.gsub!("\n", "'\n'")
77
- str
66
+ return "''" if str.empty?
67
+ str.gsub(%r{[^A-Za-z0-9_\-.,:+/@\n]}, "\\\\\\&").gsub("\n", "'\n'")
78
68
  end
79
69
  end
80
70
 
81
71
  module Input
82
- def self.for(obj)
72
+ def self.[](obj)
83
73
  return unless obj
84
- return CopyWriter.new(obj) if obj.respond_to?(:readpartial)
85
- return CopyWriter.new(obj.to_io) if obj.respond_to?(:to_io)
86
- return ArrayWriter.new(obj) if obj.is_a?(Array)
87
- return EnumerableWriter.new(obj) if obj.respond_to?(:each)
88
- return ArrayWriter.new(obj.to_a) if obj.respond_to?(:to_a)
89
- Writer.new(obj)
90
- end
91
-
92
- class Writer
93
- def call(io) = (io.write(_next) if @obj)
94
- def initialize(obj) = (@obj = obj)
95
- def _next = (_, @obj = @obj, nil).first
74
+ return copy_writer(obj) if obj.respond_to?(:readpartial)
75
+ return copy_writer(obj.to_io) if obj.respond_to?(:to_io)
76
+ return array_writer(obj) if obj.is_a?(Array)
77
+ if obj.respond_to?(:each)
78
+ return enum_writer(obj.enum_for(:each)) if obj.respond_to?(:enum_for)
79
+ return enum_writer(Enumerator.new { |y| obj.each { y << _1 } })
80
+ end
81
+ return array_writer(obj.to_a) if obj.respond_to?(:to_a)
82
+ proc do |io|
83
+ io.write(obj)
84
+ nil
85
+ end
96
86
  end
97
87
 
98
- class CopyWriter < Writer
99
- def call(io) = (IO.copy_stream(_next, io) if @obj)
88
+ def self.copy_writer(src)
89
+ proc do |trg|
90
+ IO.copy_stream(src, trg)
91
+ nil
92
+ end
100
93
  end
101
94
 
102
- class ArrayWriter
103
- def call(io) = io.write(@ry[@idx += 1] || return)
104
-
105
- def initialize(ary)
106
- @ry = ary
107
- @idx = -1
108
- end
95
+ def self.array_writer(array, idx = -1)
96
+ proc { _1.write(array[idx += 1] || next) }
109
97
  end
110
98
 
111
- class EnumerableWriter
112
- def call(io)
113
- io.write(@enum.next)
99
+ def self.enum_writer(enum)
100
+ proc do |io|
101
+ io.write(enum.next)
114
102
  rescue StopIteration
115
- false
116
- end
117
-
118
- def initialize(enum)
119
- return @enum = enum.enum_for(:each) if enum.respond_to?(:enum_for)
120
- @enum = Enumerator.new { |y| enum.each { y << _1 } }
103
+ nil
121
104
  end
122
105
  end
123
-
124
- private_constant :Writer, :CopyWriter, :ArrayWriter, :EnumerableWriter
125
106
  end
126
107
 
127
108
  private_constant :Input
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Terminal
4
4
  # The version number of the gem.
5
- VERSION = '0.17.0'
5
+ VERSION = '0.17.1'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terminal_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt