thor-interactive 0.1.0.pre.2 → 0.1.0.pre.3

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: 04a0318e910fee2ac10a134b2a9514ceef72921c2b1525d29face4c46a306ad8
4
- data.tar.gz: 1376543ed73e25721cb220893cb62fbe0fb6bc18d94ea38ecf00df60878fd4d1
3
+ metadata.gz: '049af6f0fedd7bda65c5845a878bd02afe8e9e5cf705ebad254c333e0151ecd7'
4
+ data.tar.gz: '049e366b5d3d1e4d0076c7c69d69240b00f0768b3b2687d23e9482dd7bf368dd'
5
5
  SHA512:
6
- metadata.gz: '05909f8f5c99a783831eec436ee94236b279b883c2cda0c62379081c28cc7258d8ab8317dfa4d3aba36c942f763767eed1dc08d45427ee05c00b7513f8488af9'
7
- data.tar.gz: 16a55871f6754affc2450703f3de24ecfee977ca372566b93dc44537cd3599bf305ecd988ec7f06349c786df9f0f7ab2e5bfed7d608390e53fedc6bdeb05f1cb
6
+ metadata.gz: bc5ccc2b2765f3f5c4591c181445dbc4b0ef66982c982758fb6053fa79de968c7583f019be85a747c51474e6e2f55f8834b9c4fd3314b1186dd6185a9be9e092
7
+ data.tar.gz: cc284a24f5f2a24bb016651e4252a9230d89c84d0e86b382fb4b936d11063422f78338d4c0917aedcf0a6e6d9fe7dcb66f8e7fb22c479c2903f355265e00cc79
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "thor/interactive"
6
+
7
+ class SignalDemo < Thor
8
+ include Thor::Interactive::Command
9
+
10
+ configure_interactive(
11
+ prompt: "signal> ",
12
+ ctrl_c_behavior: :clear_prompt, # Default
13
+ double_ctrl_c_timeout: 0.5 # 500ms window for double Ctrl-C
14
+ )
15
+
16
+ desc "slow", "Simulate a slow command"
17
+ def slow
18
+ puts "Starting slow operation..."
19
+ 5.times do |i|
20
+ puts "Step #{i + 1}/5"
21
+ sleep(1)
22
+ end
23
+ puts "Done!"
24
+ rescue Interrupt
25
+ puts "\nOperation cancelled!"
26
+ end
27
+
28
+ desc "loop", "Run an infinite loop (test Ctrl-C)"
29
+ def loop
30
+ puts "Starting infinite loop (press Ctrl-C to stop)..."
31
+ counter = 0
32
+ while true
33
+ print "\rCounter: #{counter}"
34
+ counter += 1
35
+ sleep(0.1)
36
+ end
37
+ rescue Interrupt
38
+ puts "\nLoop stopped at #{counter}"
39
+ end
40
+
41
+ desc "input", "Test input with special text"
42
+ def input
43
+ puts "Type something with Ctrl chars:"
44
+ puts " - Ctrl-C to clear and start over"
45
+ puts " - Ctrl-D to cancel"
46
+ puts " - Enter to submit"
47
+
48
+ print "input> "
49
+ begin
50
+ text = $stdin.gets
51
+ if text
52
+ puts "You entered: #{text.inspect}"
53
+ else
54
+ puts "Cancelled with Ctrl-D"
55
+ end
56
+ rescue Interrupt
57
+ puts "\nInterrupted - input cancelled"
58
+ end
59
+ end
60
+
61
+ desc "behaviors", "Demo different Ctrl-C behaviors"
62
+ def behaviors
63
+ puts "\n=== Ctrl-C Behavior Options ==="
64
+ puts
65
+ puts "1. :clear_prompt (default)"
66
+ puts " - Shows ^C and hint message"
67
+ puts " - Clear and friendly"
68
+
69
+ puts "\n2. :show_help"
70
+ puts " - Shows help reminder"
71
+ puts " - Good for new users"
72
+
73
+ puts "\n3. :silent"
74
+ puts " - Just clears the line"
75
+ puts " - Minimal interruption"
76
+
77
+ puts "\nYou can configure with:"
78
+ puts " configure_interactive(ctrl_c_behavior: :show_help)"
79
+ end
80
+
81
+ desc "test_clear", "Test with clear_prompt behavior"
82
+ def test_clear
83
+ puts "Starting new shell with :clear_prompt behavior"
84
+ puts "Try pressing Ctrl-C..."
85
+ puts
86
+
87
+ SignalDemo.new.interactive
88
+ end
89
+
90
+ desc "test_help", "Test with show_help behavior"
91
+ def test_help
92
+ puts "Starting new shell with :show_help behavior"
93
+ puts "Try pressing Ctrl-C..."
94
+ puts
95
+
96
+ test_app = Class.new(Thor) do
97
+ include Thor::Interactive::Command
98
+ configure_interactive(
99
+ prompt: "help> ",
100
+ ctrl_c_behavior: :show_help
101
+ )
102
+
103
+ desc "test", "Test command"
104
+ def test
105
+ puts "Test executed"
106
+ end
107
+ end
108
+
109
+ test_app.new.interactive
110
+ end
111
+
112
+ desc "test_silent", "Test with silent behavior"
113
+ def test_silent
114
+ puts "Starting new shell with :silent behavior"
115
+ puts "Try pressing Ctrl-C..."
116
+ puts
117
+
118
+ test_app = Class.new(Thor) do
119
+ include Thor::Interactive::Command
120
+ configure_interactive(
121
+ prompt: "silent> ",
122
+ ctrl_c_behavior: :silent
123
+ )
124
+
125
+ desc "test", "Test command"
126
+ def test
127
+ puts "Test executed"
128
+ end
129
+ end
130
+
131
+ test_app.new.interactive
132
+ end
133
+
134
+ desc "help_signals", "Explain signal handling"
135
+ def help_signals
136
+ puts <<~HELP
137
+
138
+ === Signal Handling in thor-interactive ===
139
+
140
+ CTRL-C (SIGINT):
141
+ Single Press:
142
+ - Clears current input line
143
+ - Shows hint about double Ctrl-C
144
+ - Returns to fresh prompt
145
+
146
+ Double Press (within 500ms):
147
+ - Exits the interactive shell
148
+ - Same as typing 'exit'
149
+
150
+ CTRL-D (EOF):
151
+ - Exits immediately
152
+ - Standard Unix EOF behavior
153
+ - Same as typing 'exit'
154
+
155
+ EXIT COMMANDS:
156
+ - exit
157
+ - quit
158
+ - q
159
+ - /exit, /quit, /q (with slash)
160
+
161
+ CONFIGURATION:
162
+ configure_interactive(
163
+ ctrl_c_behavior: :clear_prompt, # or :show_help, :silent
164
+ double_ctrl_c_timeout: 0.5 # seconds
165
+ )
166
+
167
+ BEHAVIOR OPTIONS:
168
+ :clear_prompt (default)
169
+ Shows "^C" and hint message
170
+
171
+ :show_help
172
+ Shows help reminder on Ctrl-C
173
+
174
+ :silent
175
+ Just clears the line, no message
176
+
177
+ WHY THIS DESIGN?
178
+ - Matches behavior of Python, Node.js REPLs
179
+ - Prevents accidental exit
180
+ - Clear feedback to user
181
+ - Configurable for different preferences
182
+
183
+ HELP
184
+ end
185
+
186
+ default_task :help_signals
187
+ end
188
+
189
+ if __FILE__ == $0
190
+ puts "Signal Handling Demo"
191
+ puts "==================="
192
+ puts
193
+ puts "Try these:"
194
+ puts " 1. Press Ctrl-C once (clears prompt)"
195
+ puts " 2. Press Ctrl-C twice quickly (exits)"
196
+ puts " 3. Press Ctrl-D (exits immediately)"
197
+ puts " 4. Type 'exit', 'quit', or 'q' (exits)"
198
+ puts
199
+ puts "Starting interactive shell..."
200
+ puts
201
+
202
+ SignalDemo.new.interactive
203
+ end
@@ -29,6 +29,12 @@ class Thor
29
29
  @prompt = merged_options[:prompt] || DEFAULT_PROMPT
30
30
  @history_file = File.expand_path(merged_options[:history_file] || DEFAULT_HISTORY_FILE)
31
31
 
32
+ # Ctrl-C handling configuration
33
+ @ctrl_c_behavior = merged_options[:ctrl_c_behavior] || :clear_prompt
34
+ @double_ctrl_c_timeout = merged_options.key?(:double_ctrl_c_timeout) ?
35
+ merged_options[:double_ctrl_c_timeout] : 0.5
36
+ @last_interrupt_time = nil
37
+
32
38
  setup_completion
33
39
  load_history
34
40
  end
@@ -56,27 +62,36 @@ class Thor
56
62
  puts "(Debug: Entering main loop)" if ENV["DEBUG"]
57
63
 
58
64
  loop do
59
- line = Reline.readline(display_prompt, true)
60
- puts "(Debug: Got input: #{line.inspect})" if ENV["DEBUG"]
61
-
62
- if should_exit?(line)
63
- puts "(Debug: Exit condition met)" if ENV["DEBUG"]
64
- break
65
- end
66
-
67
- next if line.nil? || line.strip.empty?
68
-
69
65
  begin
66
+ line = Reline.readline(display_prompt, true)
67
+ puts "(Debug: Got input: #{line.inspect})" if ENV["DEBUG"]
68
+
69
+ # Reset interrupt tracking on successful input
70
+ @last_interrupt_time = nil if line
71
+
72
+ if should_exit?(line)
73
+ puts "(Debug: Exit condition met)" if ENV["DEBUG"]
74
+ break
75
+ end
76
+
77
+ next if line.nil? || line.strip.empty?
78
+
70
79
  puts "(Debug: Processing input: #{line.strip})" if ENV["DEBUG"]
71
80
  process_input(line.strip)
72
81
  puts "(Debug: Input processed successfully)" if ENV["DEBUG"]
82
+
73
83
  rescue Interrupt
74
- puts "\n(Interrupted - press Ctrl+D or type 'exit' to quit)"
84
+ # Handle Ctrl-C
85
+ if handle_interrupt
86
+ break # Exit on double Ctrl-C
87
+ end
88
+ next # Continue on single Ctrl-C
89
+
75
90
  rescue SystemExit => e
76
91
  puts "A command tried to exit with code #{e.status}. Staying in interactive mode."
77
92
  puts "(Debug: SystemExit caught in main loop)" if ENV["DEBUG"]
78
93
  rescue => e
79
- puts "Error in main loop: #{e.message}"
94
+ puts "Error: #{e.message}"
80
95
  puts e.backtrace.first(5) if ENV["DEBUG"]
81
96
  puts "(Debug: Error handled, continuing loop)" if ENV["DEBUG"]
82
97
  # Continue the loop - don't let errors break the session
@@ -343,6 +358,37 @@ class Thor
343
358
  # Handle both /exit and exit for convenience
344
359
  EXIT_COMMANDS.include?(stripped) || EXIT_COMMANDS.include?(stripped.sub(/^\//, ''))
345
360
  end
361
+
362
+ def handle_interrupt
363
+ current_time = Time.now
364
+
365
+ # Check for double Ctrl-C
366
+ if @last_interrupt_time && @double_ctrl_c_timeout && (current_time - @last_interrupt_time) < @double_ctrl_c_timeout
367
+ puts "\n(Interrupted twice - exiting)"
368
+ @last_interrupt_time = nil # Reset for next time
369
+ return true # Signal to exit
370
+ end
371
+
372
+ @last_interrupt_time = current_time
373
+
374
+ # Single Ctrl-C behavior
375
+ case @ctrl_c_behavior
376
+ when :clear_prompt
377
+ puts "^C"
378
+ puts "(Press Ctrl-C again quickly or Ctrl-D to exit)"
379
+ when :show_help
380
+ puts "\n^C - Interrupt"
381
+ puts "Press Ctrl-C again to exit, or type 'help' for commands"
382
+ when :silent
383
+ # Just clear the line, no message
384
+ print "\r#{' ' * 80}\r"
385
+ else
386
+ # Default behavior
387
+ puts "^C"
388
+ end
389
+
390
+ false # Don't exit, just clear prompt
391
+ end
346
392
 
347
393
  def show_welcome(nesting_level = 0)
348
394
  if nesting_level > 0
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
+ require_relative "version_constant"
4
5
 
5
6
  class Thor
6
7
  module Interactive
7
- VERSION = "0.1.0.pre.2"
8
+ VERSION = ThorInteractive::VERSION
8
9
  end
9
10
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Version constant for thor-interactive gem
4
+ # This file is separate to avoid circular dependencies during gem installation
5
+
6
+ module ThorInteractive
7
+ VERSION = "0.1.0.pre.3"
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thor-interactive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.2
4
+ version: 0.1.0.pre.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Petersen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-07 00:00:00.000000000 Z
11
+ date: 2025-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -57,11 +57,13 @@ files:
57
57
  - examples/demo_session.rb
58
58
  - examples/nested_example.rb
59
59
  - examples/sample_app.rb
60
+ - examples/signal_demo.rb
60
61
  - examples/test_interactive.rb
61
62
  - lib/thor/interactive.rb
62
63
  - lib/thor/interactive/command.rb
63
64
  - lib/thor/interactive/shell.rb
64
65
  - lib/thor/interactive/version.rb
66
+ - lib/thor/interactive/version_constant.rb
65
67
  - sig/thor/interactive.rbs
66
68
  homepage: https://github.com/scientist-labs/thor-interactive
67
69
  licenses: