ruby_jard 0.3.0 → 0.3.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 +4 -4
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/rspec.yml +26 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +3 -0
- data/lib/ruby_jard.rb +8 -2
- data/lib/ruby_jard/commands/continue_command.rb +1 -1
- data/lib/ruby_jard/commands/exit_command.rb +1 -1
- data/lib/ruby_jard/commands/jard/output_command.rb +1 -0
- data/lib/ruby_jard/config.rb +11 -4
- data/lib/ruby_jard/console.rb +47 -19
- data/lib/ruby_jard/control_flow.rb +1 -1
- data/lib/ruby_jard/decorators/color_decorator.rb +13 -4
- data/lib/ruby_jard/decorators/rails_decorator.rb +8 -2
- data/lib/ruby_jard/keys.rb +2 -1
- data/lib/ruby_jard/pager.rb +8 -2
- data/lib/ruby_jard/repl_processor.rb +6 -4
- data/lib/ruby_jard/repl_proxy.rb +41 -16
- data/lib/ruby_jard/screen_manager.rb +8 -12
- data/lib/ruby_jard/session.rb +34 -29
- data/lib/ruby_jard/span.rb +1 -1
- data/lib/ruby_jard/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00607fcc7c6b4de0a2bb272624357ef7f9c8e3a0aa4a46783f127b094fc0a6f9
|
4
|
+
data.tar.gz: 6bd10f20ba123f290b786a875eb5879cf343e126a1a31d420387691e7ee6d5e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64ca81f056c51fd717cb1b1caae5f8490bb71ea8f5b93b587451ab8115e546fea617eb0eb0d4357a281c255ff862d33a024ccae0301a3148800dff1332242662
|
7
|
+
data.tar.gz: b1063583e9f8c31d9ec3e092e8d5e99b339b3d016b2516d2c4e9b27843071099916f8444c5bc648ba506e00d794bdecc030c06b838895385aff61981d696a6ca
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
3
|
+
# Please see the documentation for all configuration options:
|
4
|
+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
5
|
+
|
6
|
+
version: 2
|
7
|
+
updates:
|
8
|
+
- package-ecosystem: "bundler" # See documentation for possible values
|
9
|
+
directory: "/" # Location of package manifests
|
10
|
+
schedule:
|
11
|
+
interval: "daily"
|
data/.github/workflows/rspec.yml
CHANGED
@@ -32,8 +32,17 @@ jobs:
|
|
32
32
|
uses: ruby/setup-ruby@v1
|
33
33
|
with:
|
34
34
|
ruby-version: ${{ matrix.ruby }}
|
35
|
+
- uses: actions/checkout@v2
|
36
|
+
with:
|
37
|
+
repository: tmux/tmux
|
38
|
+
path: 'tmux'
|
39
|
+
ref: '3.1b'
|
40
|
+
- name: Install dependencies for tmux
|
41
|
+
run: sudo apt install -y libevent-dev
|
35
42
|
- name: Install tmux
|
36
|
-
run: sudo
|
43
|
+
run: cd tmux && sh autogen.sh && ./configure && make && sudo make install
|
44
|
+
- name: Tmux version
|
45
|
+
run: tmux -V
|
37
46
|
- name: Start tmux
|
38
47
|
run: tmux start-server
|
39
48
|
- name: Start dummy tmux session
|
@@ -42,6 +51,8 @@ jobs:
|
|
42
51
|
run: ruby spec/wait_for_tmux.rb
|
43
52
|
- name: Install dependencies
|
44
53
|
run: bundle install
|
54
|
+
- name: Kill tmux
|
55
|
+
run: tmux kill-server || true
|
45
56
|
- name: Run tests
|
46
57
|
run: bundle exec parallel_rspec spec/
|
47
58
|
test-macos:
|
@@ -69,28 +80,39 @@ jobs:
|
|
69
80
|
- name: Run tests
|
70
81
|
run: bundle exec parallel_rspec -n 2 spec/
|
71
82
|
test-byebug:
|
72
|
-
runs-on: ubuntu-latest
|
73
83
|
strategy:
|
74
84
|
fail-fast: false
|
75
85
|
matrix:
|
76
86
|
byebug: [9.1.0, 10.0.2]
|
77
87
|
env:
|
78
88
|
BUNDLE_GEMFILE: "./spec/gemfiles/Gemfile-byebug-${{ matrix.byebug }}"
|
89
|
+
runs-on: ubuntu-latest
|
79
90
|
steps:
|
80
91
|
- uses: actions/checkout@v2
|
81
92
|
- name: Set up Ruby
|
82
93
|
uses: ruby/setup-ruby@v1
|
83
94
|
with:
|
84
95
|
ruby-version: 2.5
|
96
|
+
- uses: actions/checkout@v2
|
97
|
+
with:
|
98
|
+
repository: tmux/tmux
|
99
|
+
path: 'tmux'
|
100
|
+
ref: '3.1b'
|
101
|
+
- name: Install dependencies for tmux
|
102
|
+
run: sudo apt install -y libevent-dev
|
85
103
|
- name: Install tmux
|
86
|
-
run: sudo
|
104
|
+
run: cd tmux && sh autogen.sh && ./configure && make && sudo make install
|
105
|
+
- name: Tmux version
|
106
|
+
run: tmux -V
|
87
107
|
- name: Start tmux
|
88
108
|
run: tmux start-server
|
89
|
-
- name:
|
109
|
+
- name: Start dummy tmux session
|
90
110
|
run: tmux new-session -t dummy -d
|
91
111
|
- name: Wait for tmux
|
92
112
|
run: ruby spec/wait_for_tmux.rb
|
93
113
|
- name: Install dependencies
|
94
114
|
run: bundle install
|
115
|
+
- name: Kill tmux
|
116
|
+
run: tmux kill-server || true
|
95
117
|
- name: Run tests
|
96
118
|
run: bundle exec parallel_rspec spec/
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.3.1]
|
4
|
+
This release fixes bunch of bugs, and performance issues reported by the users after beta launch. No new features are introduced.
|
5
|
+
|
6
|
+
- Pry and Byebug backward compatibility: [#39](https://github.com/nguyenquangminh0711/ruby_jard/issues/39), [#45](https://github.com/nguyenquangminh0711/ruby_jard/issues/45)
|
7
|
+
- Error with non-UTF8 encoding in the output: [#55](https://github.com/nguyenquangminh0711/ruby_jard/issues/55)
|
8
|
+
- Ctrl+D not working: [#34](https://github.com/nguyenquangminh0711/ruby_jard/issues/34)
|
9
|
+
- Errors if putting jard with `<%= jard %>` in ERB: [#35](https://github.com/nguyenquangminh0711/ruby_jard/issues/35)
|
10
|
+
- Handle standard stream redirections, and prevent Jard from attachment in invalid TTY device: [#38](https://github.com/nguyenquangminh0711/ruby_jard/issues/38), [#46](https://github.com/nguyenquangminh0711/ruby_jard/issues/46), [#53](https://github.com/nguyenquangminh0711/ruby_jard/issues/53)
|
11
|
+
- Bring back auto-resize when window size changes: [#40](https://github.com/nguyenquangminh0711/ruby_jard/issues/40)
|
12
|
+
- Improve performance after `exit` command: [#49](https://github.com/nguyenquangminh0711/ruby_jard/issues/49)
|
13
|
+
- Handle edge cases in Jard color decorator: [#54](https://github.com/nguyenquangminh0711/ruby_jard/issues/54)
|
14
|
+
- Escape all special characters and line feeds before printing stuff into the screen: [#57](https://github.com/nguyenquangminh0711/ruby_jard/issues/57)
|
15
|
+
|
3
16
|
## [0.3.0 - Beta 1]
|
4
17
|
- Filter feature
|
5
18
|
- New variable screen look and feel
|
data/Gemfile
CHANGED
data/lib/ruby_jard.rb
CHANGED
@@ -14,7 +14,6 @@ require 'ruby_jard/keys'
|
|
14
14
|
require 'ruby_jard/key_binding'
|
15
15
|
require 'ruby_jard/key_bindings'
|
16
16
|
require 'ruby_jard/repl_proxy'
|
17
|
-
require 'ruby_jard/repl_processor'
|
18
17
|
require 'ruby_jard/screen_manager'
|
19
18
|
require 'ruby_jard/reflection'
|
20
19
|
|
@@ -98,13 +97,20 @@ module RubyJard
|
|
98
97
|
def self.config
|
99
98
|
@config ||= RubyJard::Config.smart_load
|
100
99
|
end
|
100
|
+
|
101
|
+
def self.all_files
|
102
|
+
Dir.glob(File.join(File.expand_path(__dir__, './lib'), '**', '*.rb')) +
|
103
|
+
Dir.glob(File.join(File.expand_path(__dir__, './lib'), '*.rb')) +
|
104
|
+
Dir.glob(File.join(File.expand_path(__dir__, './bin'), '**', '*.rb')) +
|
105
|
+
Dir.glob(File.join(File.expand_path(__dir__, './bin'), '*.rb'))
|
106
|
+
end
|
101
107
|
end
|
102
108
|
|
103
109
|
##
|
104
110
|
# Monkey-patch Kernel module to allow putting jard command anywhere.
|
105
111
|
module Kernel
|
106
112
|
def jard
|
107
|
-
RubyJard::Session.
|
113
|
+
RubyJard::Session.attach
|
108
114
|
end
|
109
115
|
|
110
116
|
if RubyJard.config.alias_to_debugger
|
@@ -14,7 +14,7 @@ module RubyJard
|
|
14
14
|
Examples:
|
15
15
|
continue
|
16
16
|
|
17
|
-
Continue
|
17
|
+
Continue the execution of your program to the end, or stop at the first dynamic break point or `jard` attachment command.
|
18
18
|
BANNER
|
19
19
|
|
20
20
|
def process
|
@@ -14,7 +14,7 @@ module RubyJard
|
|
14
14
|
Examples:
|
15
15
|
exit
|
16
16
|
|
17
|
-
Exit
|
17
|
+
Exit the execution of the program. Interally, when `jard` receives this command, it removes all debugging hooks, and triggers `::Kernel.exit`. Some long-running processes like `puma` or `sidekiq` may capture this event, treat it as an error, and recover to keep the processes running. In such cases, it's recommended to use `continue` command instead.
|
18
18
|
BANNER
|
19
19
|
|
20
20
|
def process
|
data/lib/ruby_jard/config.rb
CHANGED
@@ -8,6 +8,14 @@ module RubyJard
|
|
8
8
|
def smart_load
|
9
9
|
config = RubyJard::Config.new
|
10
10
|
|
11
|
+
unless ENV['JARD_CONFIG_FILE'].nil?
|
12
|
+
unless File.exist?(ENV['JARD_CONFIG_FILE'])
|
13
|
+
raise "Config file '#{ENV['JARD_CONFIG_FILE']}' does not exist"
|
14
|
+
end
|
15
|
+
|
16
|
+
return load_config(config, ENV['JARD_CONFIG_FILE'])
|
17
|
+
end
|
18
|
+
|
11
19
|
path = File.expand_path(File.join(Dir.pwd, CONFIG_FILE_NAME))
|
12
20
|
load_config(config, path) if File.exist?(path)
|
13
21
|
|
@@ -15,10 +23,6 @@ module RubyJard
|
|
15
23
|
load_config(config, path) if File.exist?(path)
|
16
24
|
|
17
25
|
config
|
18
|
-
rescue StandardError => e
|
19
|
-
# Fallback to default setting
|
20
|
-
STDOUT.puts "Fail to load jard configurations at #{path}. Error: #{e}"
|
21
|
-
RubyJard::Config.new
|
22
26
|
end
|
23
27
|
|
24
28
|
private
|
@@ -28,6 +32,9 @@ module RubyJard
|
|
28
32
|
config.instance_eval(config_content)
|
29
33
|
|
30
34
|
config
|
35
|
+
rescue SyntaxError, StandardError => e
|
36
|
+
# Fallback to default setting
|
37
|
+
raise "Fail to load jard configurations at #{path}. Error: #{e}"
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
data/lib/ruby_jard/console.rb
CHANGED
@@ -8,22 +8,45 @@ module RubyJard
|
|
8
8
|
# Wrapper for utilities to control screen
|
9
9
|
class Console
|
10
10
|
class << self
|
11
|
-
def
|
12
|
-
return unless output.tty?
|
11
|
+
def attachable?
|
12
|
+
return false unless output.tty?
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
# If tput not found, fallback to hard-coded sequence.
|
17
|
-
output.print "\e[?1049h\e[22;0;0t"
|
14
|
+
width, height = screen_size(output)
|
15
|
+
width != 0 && height != 0
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
21
|
-
|
18
|
+
def redirected?
|
19
|
+
output != $stdout
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
output
|
22
|
+
def output
|
23
|
+
return @output if defined?(@output)
|
24
|
+
|
25
|
+
@output =
|
26
|
+
if STDOUT.tty?
|
27
|
+
STDOUT
|
28
|
+
else
|
29
|
+
begin
|
30
|
+
File.open('/dev/tty', 'w+')
|
31
|
+
rescue StandardError
|
32
|
+
STDOUT # Give up now.
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def input
|
38
|
+
return @input if defined?(@input)
|
39
|
+
|
40
|
+
@input =
|
41
|
+
if STDIN.tty?
|
42
|
+
STDIN
|
43
|
+
else
|
44
|
+
begin
|
45
|
+
File.open('/dev/tty', 'r+')
|
46
|
+
rescue StandardError
|
47
|
+
STDIN # Give up.
|
48
|
+
end
|
49
|
+
end
|
27
50
|
end
|
28
51
|
|
29
52
|
def move_to(output, x, y)
|
@@ -35,7 +58,12 @@ module RubyJard
|
|
35
58
|
def screen_size(output)
|
36
59
|
return [0, 0] unless output.tty?
|
37
60
|
|
38
|
-
|
61
|
+
if output.respond_to?(:winsize)
|
62
|
+
height, width = output.winsize
|
63
|
+
[width, height]
|
64
|
+
else
|
65
|
+
[TTY::Screen.width, TTY::Screen.height]
|
66
|
+
end
|
39
67
|
end
|
40
68
|
|
41
69
|
def clear_screen(output)
|
@@ -50,7 +78,7 @@ module RubyJard
|
|
50
78
|
output.print "\e[0J"
|
51
79
|
end
|
52
80
|
|
53
|
-
def disable_cursor!(output
|
81
|
+
def disable_cursor!(output)
|
54
82
|
return unless output.tty?
|
55
83
|
|
56
84
|
output.print tput('civis')
|
@@ -59,7 +87,7 @@ module RubyJard
|
|
59
87
|
output.print "\e[?25l"
|
60
88
|
end
|
61
89
|
|
62
|
-
def enable_cursor!(output
|
90
|
+
def enable_cursor!(output)
|
63
91
|
return unless output.tty?
|
64
92
|
|
65
93
|
output.print tput('cnorm')
|
@@ -81,7 +109,7 @@ module RubyJard
|
|
81
109
|
nil
|
82
110
|
end
|
83
111
|
|
84
|
-
def raw!(output
|
112
|
+
def raw!(output)
|
85
113
|
return unless output.tty?
|
86
114
|
|
87
115
|
begin
|
@@ -91,7 +119,7 @@ module RubyJard
|
|
91
119
|
end
|
92
120
|
end
|
93
121
|
|
94
|
-
def cooked!(output
|
122
|
+
def cooked!(output)
|
95
123
|
return unless output.tty?
|
96
124
|
|
97
125
|
begin
|
@@ -102,7 +130,7 @@ module RubyJard
|
|
102
130
|
end
|
103
131
|
end
|
104
132
|
|
105
|
-
def disable_echo!(output
|
133
|
+
def disable_echo!(output)
|
106
134
|
return unless output.tty?
|
107
135
|
|
108
136
|
begin
|
@@ -113,7 +141,7 @@ module RubyJard
|
|
113
141
|
end
|
114
142
|
end
|
115
143
|
|
116
|
-
def enable_echo!(output
|
144
|
+
def enable_echo!(output)
|
117
145
|
return unless output.tty?
|
118
146
|
|
119
147
|
begin
|
@@ -37,17 +37,28 @@ module RubyJard
|
|
37
37
|
|
38
38
|
def decorate(style_names, content)
|
39
39
|
attributes = nil
|
40
|
+
foreground = nil
|
41
|
+
background = nil
|
42
|
+
|
40
43
|
if style_names.is_a?(Symbol)
|
41
44
|
styles = @color_scheme.styles_for(style_names)
|
42
45
|
else
|
43
46
|
attributes = translate_styles(style_names)
|
44
47
|
styles = @color_scheme.styles_for(style_names.shift)
|
45
48
|
end
|
46
|
-
|
47
|
-
|
49
|
+
|
50
|
+
if styles.is_a?(Array)
|
51
|
+
foreground = translate_color(styles.shift, true)
|
52
|
+
background = translate_color(styles.shift, false)
|
53
|
+
elsif !styles.nil?
|
54
|
+
raise RubyJard::Error, "Styles for #{style_names.inspect} must be an array"
|
55
|
+
end
|
56
|
+
|
48
57
|
"#{foreground}#{background}#{attributes}#{content}#{CSI_RESET}"
|
49
58
|
end
|
50
59
|
|
60
|
+
private
|
61
|
+
|
51
62
|
def translate_color(color, foreground)
|
52
63
|
if (matches = HEX_PATTERN_6.match(color.to_s))
|
53
64
|
red = matches[1].to_i(16)
|
@@ -70,8 +81,6 @@ module RubyJard
|
|
70
81
|
end
|
71
82
|
end
|
72
83
|
|
73
|
-
private
|
74
|
-
|
75
84
|
def translate_styles(styles = [])
|
76
85
|
styles.map { |key| STYLES_CSI_MAP[key] }.compact.join
|
77
86
|
end
|
@@ -89,7 +89,9 @@ module RubyJard
|
|
89
89
|
if variable.respond_to?(:loaded?) && variable.loaded?
|
90
90
|
spans = []
|
91
91
|
label = RubyJard::Span.new(
|
92
|
-
content: RubyJard::Reflection.call_to_s(variable).chomp('>'),
|
92
|
+
content: RubyJard::Reflection.call_to_s(variable).chomp('>'),
|
93
|
+
styles: :text_primary,
|
94
|
+
margin_right: variable.length >= 1 ? 1 : 0
|
93
95
|
)
|
94
96
|
spans << label
|
95
97
|
spans += @attributes_decorator.inline_values(
|
@@ -99,6 +101,10 @@ module RubyJard
|
|
99
101
|
)
|
100
102
|
spans << RubyJard::Span.new(content: '>', styles: :text_primary)
|
101
103
|
|
104
|
+
if variable.length <= 0
|
105
|
+
spans << RubyJard::Span.new(content: '(empty)', margin_left: 1, styles: :text_primary)
|
106
|
+
end
|
107
|
+
|
102
108
|
spans
|
103
109
|
else
|
104
110
|
relation_summary(variable, line_limit)
|
@@ -138,7 +144,7 @@ module RubyJard
|
|
138
144
|
width = overview.length + 1 + 12
|
139
145
|
spans = [RubyJard::Span.new(content: overview, styles: :text_primary)]
|
140
146
|
if RubyJard::Reflection.call_respond_to?(variable, :to_sql) && width < line_limit
|
141
|
-
detail = variable.to_sql
|
147
|
+
detail = variable.to_sql.inspect
|
142
148
|
detail = detail[0..line_limit - width - 2] + '…' if width + detail.length < line_limit
|
143
149
|
spans << RubyJard::Span.new(content: detail, styles: :text_dim, margin_left: 1)
|
144
150
|
end
|
data/lib/ruby_jard/keys.rb
CHANGED
@@ -42,7 +42,8 @@ module RubyJard
|
|
42
42
|
F7 => (ACTION_STEP = :step),
|
43
43
|
SHIFT_F7 => (ACTION_STEP_OUT = :step_out),
|
44
44
|
F8 => (ACTION_NEXT = :next),
|
45
|
-
F9 => (ACTION_CONTINUE = :continue)
|
45
|
+
F9 => (ACTION_CONTINUE = :continue),
|
46
|
+
CTRL_D => ACTION_CONTINUE
|
46
47
|
}.freeze
|
47
48
|
end
|
48
49
|
end
|
data/lib/ruby_jard/pager.rb
CHANGED
@@ -46,7 +46,13 @@ module RubyJard
|
|
46
46
|
@pager_start_at_the_end = pager_start_at_the_end
|
47
47
|
@prompt = prompt
|
48
48
|
|
49
|
-
|
49
|
+
# There are two cases:
|
50
|
+
# - If the real pager (less) is triggered, it works on a real tty (fetched
|
51
|
+
# from /dev/tty), in which, the same as RubyJard::Console.output
|
52
|
+
# - Otherwise, it writes directly into pry's REPL output.
|
53
|
+
# That's why there should be two output here
|
54
|
+
@tty_output = RubyJard::Console.redirected? ? RubyJard::Console.output : pry_instance.output
|
55
|
+
@window_width, @window_height = RubyJard::Console.screen_size(RubyJard::Console.output)
|
50
56
|
@tracker = JardPageTracker.new(@window_height, @window_width)
|
51
57
|
@pager = force_open ? open_pager : nil
|
52
58
|
end
|
@@ -93,7 +99,7 @@ module RubyJard
|
|
93
99
|
|
94
100
|
IO.popen(
|
95
101
|
less_command.join(' '), 'w',
|
96
|
-
out: @
|
102
|
+
out: @tty_output, err: @tty_output
|
97
103
|
)
|
98
104
|
end
|
99
105
|
|
@@ -29,7 +29,8 @@ module RubyJard
|
|
29
29
|
@repl_proxy = RubyJard::ReplProxy.new(
|
30
30
|
key_bindings: RubyJard.global_key_bindings
|
31
31
|
)
|
32
|
-
@previous_flow =
|
32
|
+
@previous_flow = RubyJard::ControlFlow.new(:next)
|
33
|
+
@output = RubyJard::Console.output
|
33
34
|
end
|
34
35
|
|
35
36
|
def at_line
|
@@ -123,10 +124,10 @@ module RubyJard
|
|
123
124
|
next_frame = find_frame(options[:frame].to_i)
|
124
125
|
if next_frame.nil?
|
125
126
|
# There must be an error in outer validators
|
126
|
-
|
127
|
+
@output.puts 'Error: Frame not found. There should be an error with Jard.'
|
127
128
|
process_commands(false)
|
128
129
|
elsif next_frame.c_frame?
|
129
|
-
|
130
|
+
@output.puts "Error: Frame #{next_frame} is a c-frame. Not able to inspect c layer!"
|
130
131
|
process_commands(false)
|
131
132
|
else
|
132
133
|
RubyJard::Session.frame = next_frame.real_pos
|
@@ -135,11 +136,12 @@ module RubyJard
|
|
135
136
|
end
|
136
137
|
|
137
138
|
def handle_continue_command(_options = {})
|
138
|
-
|
139
|
+
@output.puts '▸▸ Program resumed ▸▸'
|
139
140
|
Byebug.stop if Byebug.stoppable?
|
140
141
|
end
|
141
142
|
|
142
143
|
def handle_exit_command(_options = {})
|
144
|
+
Byebug.stop if Byebug.stoppable?
|
143
145
|
Kernel.exit
|
144
146
|
end
|
145
147
|
|
data/lib/ruby_jard/repl_proxy.rb
CHANGED
@@ -123,7 +123,10 @@ module RubyJard
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
-
def initialize(key_bindings: nil)
|
126
|
+
def initialize(key_bindings: nil, input: RubyJard::Console.input, output: RubyJard::Console.output)
|
127
|
+
@input = input
|
128
|
+
@output = output
|
129
|
+
|
127
130
|
@state = ReplState.new
|
128
131
|
|
129
132
|
@pry_input_pipe_read, @pry_input_pipe_write = IO.pipe
|
@@ -137,15 +140,23 @@ module RubyJard
|
|
137
140
|
|
138
141
|
@pry_pty_output_thread = Thread.new { pry_pty_output }
|
139
142
|
@pry_pty_output_thread.name = '<<Jard: Pty Output Thread>>'
|
143
|
+
|
144
|
+
Signal.trap('SIGWINCH') do
|
145
|
+
@main_thread.raise FlowInterrupt.new('Resize event', RubyJard::ControlFlow.new(:list))
|
146
|
+
end
|
140
147
|
end
|
141
148
|
|
149
|
+
# rubocop:disable Metrics/MethodLength
|
142
150
|
def repl(current_binding)
|
143
151
|
@state.ready!
|
144
152
|
@openning_pager = false
|
145
153
|
|
146
|
-
RubyJard::Console.disable_echo!
|
147
|
-
RubyJard::Console.raw!
|
154
|
+
RubyJard::Console.disable_echo!(@output)
|
155
|
+
RubyJard::Console.raw!(@output)
|
148
156
|
|
157
|
+
# Internally, Pry sneakily updates Readline to global output config
|
158
|
+
# when STDOUT is piping regardless of what I pass into Pry instance.
|
159
|
+
Pry.config.output = @pry_output_pty_write
|
149
160
|
Readline.input = @pry_input_pipe_read
|
150
161
|
Readline.output = @pry_output_pty_write
|
151
162
|
@pry.binding_stack.clear
|
@@ -168,41 +179,47 @@ module RubyJard
|
|
168
179
|
sleep PTY_OUTPUT_TIMEOUT until @state.exited?
|
169
180
|
RubyJard::ControlFlow.dispatch(e.flow)
|
170
181
|
ensure
|
171
|
-
RubyJard::Console.enable_echo!
|
172
|
-
RubyJard::Console.cooked!
|
173
|
-
Readline.input =
|
174
|
-
Readline.output =
|
182
|
+
RubyJard::Console.enable_echo!(@output)
|
183
|
+
RubyJard::Console.cooked!(@output)
|
184
|
+
Readline.input = @input
|
185
|
+
Readline.output = @output
|
186
|
+
Pry.config.output = @output
|
175
187
|
@key_listen_thread&.exit if @key_listen_thread&.alive?
|
176
188
|
@pry_input_thread&.exit if @pry_input_thread&.alive?
|
177
189
|
@state.exited!
|
178
190
|
end
|
191
|
+
# rubocop:enable Metrics/MethodLength
|
179
192
|
|
180
193
|
private
|
181
194
|
|
182
195
|
def read_key
|
183
|
-
RubyJard::Console.getch(
|
196
|
+
RubyJard::Console.getch(@input, KEY_READ_TIMEOUT)
|
184
197
|
end
|
185
198
|
|
186
199
|
def pry_pty_output
|
187
200
|
loop do
|
188
201
|
if @state.exiting?
|
189
202
|
if @pry_output_pty_read.ready?
|
190
|
-
|
203
|
+
write_output(@pry_output_pty_read.read_nonblock(2048))
|
191
204
|
else
|
192
205
|
@state.exited!
|
193
206
|
end
|
194
207
|
elsif @state.exited?
|
195
208
|
sleep PTY_OUTPUT_TIMEOUT
|
196
209
|
else
|
197
|
-
|
198
|
-
unless
|
199
|
-
|
210
|
+
content = @pry_output_pty_read.read_nonblock(2048)
|
211
|
+
unless content.nil?
|
212
|
+
write_output(content)
|
200
213
|
end
|
201
214
|
end
|
202
215
|
rescue IO::WaitReadable, IO::WaitWritable
|
203
216
|
# Retry
|
204
217
|
sleep PTY_OUTPUT_TIMEOUT
|
205
218
|
end
|
219
|
+
rescue StandardError
|
220
|
+
# This thread shoud never die, or the user may be freezed, and cannot type anything
|
221
|
+
sleep 0.5
|
222
|
+
retry
|
206
223
|
end
|
207
224
|
|
208
225
|
def pry_repl(current_binding)
|
@@ -312,25 +329,33 @@ module RubyJard
|
|
312
329
|
def pry_hooks
|
313
330
|
hooks = Pry::Hooks.default
|
314
331
|
hooks.add_hook(:after_read, :jard_proxy_acquire_lock) do |_read_string, _pry|
|
315
|
-
RubyJard::Console.cooked!
|
332
|
+
RubyJard::Console.cooked!(@output)
|
316
333
|
@state.processing!
|
317
334
|
# Sleep 2 ticks, wait for pry to print out all existing output in the queue
|
318
335
|
sleep PTY_OUTPUT_TIMEOUT * 2
|
319
336
|
end
|
320
337
|
hooks.add_hook(:after_handle_line, :jard_proxy_release_lock) do
|
321
|
-
RubyJard::Console.raw!
|
338
|
+
RubyJard::Console.raw!(@output)
|
322
339
|
@state.ready!
|
323
340
|
end
|
324
341
|
hooks.add_hook(:before_pager, :jard_proxy_before_pager) do
|
325
342
|
@openning_pager = true
|
326
343
|
|
327
344
|
@state.processing!
|
328
|
-
RubyJard::Console.cooked!
|
345
|
+
RubyJard::Console.cooked!(@output)
|
329
346
|
end
|
330
347
|
hooks.add_hook(:after_pager, :jard_proxy_after_pager) do
|
331
348
|
@openning_pager = false
|
332
349
|
@state.ready!
|
333
|
-
RubyJard::Console.raw!
|
350
|
+
RubyJard::Console.raw!(@output)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def write_output(content)
|
355
|
+
if RubyJard::Console.redirected?
|
356
|
+
@output.write content.force_encoding('UTF-8')
|
357
|
+
else
|
358
|
+
@output.write content.force_encoding('UTF-8'), from_jard: true
|
334
359
|
end
|
335
360
|
end
|
336
361
|
end
|
@@ -38,7 +38,7 @@ module RubyJard
|
|
38
38
|
|
39
39
|
attr_reader :output, :output_storage
|
40
40
|
|
41
|
-
def initialize(output:
|
41
|
+
def initialize(output: RubyJard::Console.output)
|
42
42
|
@output = output
|
43
43
|
@screens = {}
|
44
44
|
@started = false
|
@@ -68,9 +68,9 @@ module RubyJard
|
|
68
68
|
|
69
69
|
@started = false
|
70
70
|
|
71
|
-
RubyJard::Console.cooked!
|
72
|
-
RubyJard::Console.enable_echo!
|
73
|
-
RubyJard::Console.enable_cursor!
|
71
|
+
RubyJard::Console.cooked!(@output)
|
72
|
+
RubyJard::Console.enable_echo!(@output)
|
73
|
+
RubyJard::Console.enable_cursor!(@output)
|
74
74
|
end
|
75
75
|
|
76
76
|
def draw_screens
|
@@ -78,7 +78,7 @@ module RubyJard
|
|
78
78
|
@updating = true
|
79
79
|
|
80
80
|
RubyJard::Console.clear_screen(@output)
|
81
|
-
RubyJard::Console.disable_cursor!
|
81
|
+
RubyJard::Console.disable_cursor!(@output)
|
82
82
|
width, height = RubyJard::Console.screen_size(@output)
|
83
83
|
|
84
84
|
@layouts = calculate_layouts(width, height)
|
@@ -102,9 +102,9 @@ module RubyJard
|
|
102
102
|
draw_error(e, height)
|
103
103
|
ensure
|
104
104
|
# You don't want to mess up previous user TTY no matter happens
|
105
|
-
RubyJard::Console.cooked!
|
106
|
-
RubyJard::Console.enable_echo!
|
107
|
-
RubyJard::Console.enable_cursor!
|
105
|
+
RubyJard::Console.cooked!(@output)
|
106
|
+
RubyJard::Console.enable_echo!(@output)
|
107
|
+
RubyJard::Console.enable_cursor!(@output)
|
108
108
|
@updating = false
|
109
109
|
end
|
110
110
|
|
@@ -128,10 +128,6 @@ module RubyJard
|
|
128
128
|
RubyJard.error(exception)
|
129
129
|
end
|
130
130
|
|
131
|
-
def puts(content)
|
132
|
-
@output.write "#{content}\n", from_jard: true
|
133
|
-
end
|
134
|
-
|
135
131
|
private
|
136
132
|
|
137
133
|
def calculate_layouts(width, height)
|
data/lib/ruby_jard/session.rb
CHANGED
@@ -13,7 +13,7 @@ module RubyJard
|
|
13
13
|
extend Forwardable
|
14
14
|
|
15
15
|
def_delegators :instance,
|
16
|
-
:
|
16
|
+
:lock,
|
17
17
|
:sync, :should_stop?,
|
18
18
|
:step_over, :step_into, :frame=,
|
19
19
|
:threads, :current_frame, :current_thread, :current_backtrace,
|
@@ -22,6 +22,21 @@ module RubyJard
|
|
22
22
|
def instance
|
23
23
|
@instance ||= new
|
24
24
|
end
|
25
|
+
|
26
|
+
def attach
|
27
|
+
unless RubyJard::Console.attachable?
|
28
|
+
$stdout.puts 'Failed to attach. Jard could not detect a valid tty device.'
|
29
|
+
$stdout.puts 'This bug occurs when the process Jard trying to access is a non-interactive environment '\
|
30
|
+
' such as docker, daemon, sub-processes, etc.'
|
31
|
+
$stdout.puts 'If you are confused, please submit an issue in https://github.com/nguyenquangminh0711/ruby_jard/issues.'
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
instance.start unless instance.started?
|
36
|
+
|
37
|
+
Byebug.attach
|
38
|
+
Byebug.current_context.step_out(3, true)
|
39
|
+
end
|
25
40
|
end
|
26
41
|
|
27
42
|
OUTPUT_BUFFER_LENGTH = 10_000 # 10k lines
|
@@ -52,31 +67,28 @@ module RubyJard
|
|
52
67
|
Byebug::Setting[:autolist] = false
|
53
68
|
Byebug::Setting[:autoirb] = false
|
54
69
|
Byebug::Setting[:autopry] = false
|
70
|
+
|
71
|
+
require 'ruby_jard/repl_processor'
|
55
72
|
Byebug::Context.processor = RubyJard::ReplProcessor
|
56
73
|
# Exclude all files in Ruby Jard source code from the stacktrace.
|
57
|
-
Byebug::Context.ignored_files = Byebug::Context.all_files +
|
58
|
-
File.join(
|
59
|
-
File.expand_path(__dir__, '../lib'),
|
60
|
-
'**',
|
61
|
-
'*.rb'
|
62
|
-
)
|
63
|
-
)
|
64
|
-
# rubocop:disable Lint/NestedMethodDefinition
|
65
|
-
def $stdout.write(*string, from_jard: false)
|
66
|
-
# NOTE: `RubyJard::ScreenManager.instance` is a must. Jard doesn't work well with delegator
|
67
|
-
# TODO: Debug and fix the issues permanently
|
68
|
-
if from_jard
|
69
|
-
super(*string)
|
70
|
-
return
|
71
|
-
end
|
74
|
+
Byebug::Context.ignored_files = Byebug::Context.all_files + RubyJard.all_files
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
$stdout.send(:instance_eval, <<-CODE)
|
77
|
+
def write(*string, from_jard: false)
|
78
|
+
# NOTE: `RubyJard::ScreenManager.instance` is a must. Jard doesn't work well with delegator
|
79
|
+
# TODO: Debug and fix the issues permanently
|
80
|
+
if from_jard
|
81
|
+
super(*string)
|
82
|
+
return
|
83
|
+
end
|
76
84
|
|
77
|
-
|
78
|
-
|
79
|
-
|
85
|
+
unless RubyJard::ScreenManager.instance.updating?
|
86
|
+
RubyJard::Session.instance.append_output_buffer(string)
|
87
|
+
end
|
88
|
+
|
89
|
+
super(*string)
|
90
|
+
end
|
91
|
+
CODE
|
80
92
|
|
81
93
|
at_exit { stop }
|
82
94
|
|
@@ -98,13 +110,6 @@ module RubyJard
|
|
98
110
|
@started == true
|
99
111
|
end
|
100
112
|
|
101
|
-
def attach
|
102
|
-
start unless started?
|
103
|
-
|
104
|
-
Byebug.attach
|
105
|
-
Byebug.current_context.step_out(3, true)
|
106
|
-
end
|
107
|
-
|
108
113
|
def should_stop?
|
109
114
|
@path_filter.match?(@current_context.frame_file)
|
110
115
|
end
|
data/lib/ruby_jard/span.rb
CHANGED
data/lib/ruby_jard/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_jard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Minh Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- ".github/FUNDING.yml"
|
71
71
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
72
72
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
73
|
+
- ".github/dependabot.yml"
|
73
74
|
- ".github/workflows/documentation.yml"
|
74
75
|
- ".github/workflows/rspec.yml"
|
75
76
|
- ".gitignore"
|