scryglass 0.1.0 → 2.0.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.
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Scryglass
4
+ class SessionManager
5
+ using AnsilessStringRefinement
6
+ using ArrayFitToRefinement
7
+ using ClipStringRefinement
8
+
9
+ attr_accessor :scry_sessions
10
+ attr_accessor :binding_trackers_by_receiver
11
+ attr_accessor :current_binding_receiver
12
+ attr_accessor :unused_tab_icons
13
+
14
+ SESSION_CLOSED_MESSAGE = '(Exited scry! Resume session with just `scry`)'
15
+
16
+ NAMED_VARIABLES_MESSAGE = "\nCustom instance variables:"
17
+
18
+ def initialize
19
+ self.scry_sessions = []
20
+ self.binding_trackers_by_receiver = {}
21
+ self.current_binding_receiver = nil
22
+
23
+ alphabet = ('A'..'Z').to_a
24
+ digits = ('2'..'9').to_a
25
+ self.unused_tab_icons =
26
+ alphabet + digits.product(alphabet).map { |pair| pair.reverse.join }
27
+ end
28
+
29
+ # For consistency, we reference the same binding tracker (and thus
30
+ # console_binding) every time for a given receiver.
31
+ def track_binding!(console_binding)
32
+ self.current_binding_receiver = console_binding.receiver
33
+ self.binding_trackers_by_receiver[current_binding_receiver] ||=
34
+ Scryglass::BindingTracker.new(console_binding: console_binding)
35
+ end
36
+
37
+ def <<(session)
38
+ set_current_session!(session)
39
+ session.session_manager = self
40
+ session.tab_icon = unused_tab_icons.shift
41
+ # TODO: name that session?
42
+ self.scry_sessions << session
43
+ end
44
+
45
+ def session_tabs_bar
46
+ _screen_height, screen_width = $stdout.winsize
47
+
48
+ tab_indicators = scry_sessions.map do |session|
49
+ session.tab_string.clip_at(screen_width / 3, ignore_ansi_codes: true)
50
+ end
51
+
52
+ compressed_tab_indicators = tab_indicators.compress_to(screen_width, ignore_ansi_codes: true)
53
+
54
+ packed_tabs = compressed_tab_indicators.join
55
+ pad_length = screen_width - packed_tabs.ansiless_length
56
+ packed_tabs + ('#' * pad_length) + "\n" + ('#' * screen_width)
57
+ end
58
+
59
+ def current_session
60
+ scry_sessions.find(&:session_is_current)
61
+ end
62
+
63
+ def current_console_binding
64
+ current_binding_tracker.console_binding
65
+ end
66
+
67
+ def run_scry_ui
68
+ while current_session
69
+ session_return = current_session.run_scry_ui
70
+
71
+ case current_session.signal_to_manager
72
+ when :return
73
+ visually_close_ui
74
+ return session_return
75
+ when :quit
76
+ visually_close_ui
77
+ return
78
+ when :quit_from_help
79
+ visually_close_ui(floor_the_cursor: true)
80
+ return
81
+ when :delete
82
+ old_session = current_session
83
+ visually_close_ui
84
+ if scry_sessions.index(old_session) > 0
85
+ change_session_left!
86
+ else
87
+ change_session_right!
88
+ end
89
+ delete_session!(old_session)
90
+ when :change_session_left # and if there's only one session?
91
+ change_session_left!
92
+ when :change_session_right # and if there's only one session?
93
+ change_session_right!
94
+ end
95
+ end
96
+ end
97
+
98
+ def current_binding_tracker
99
+ binding_trackers_by_receiver[current_binding_receiver]
100
+ end
101
+
102
+ def current_user_named_variables
103
+ current_binding_tracker.user_named_variables
104
+ end
105
+
106
+ private
107
+
108
+ def visually_close_ui(floor_the_cursor: false)
109
+ _screen_height, screen_width = $stdout.winsize
110
+ current_session.set_console_cursor_below_content(
111
+ floor_the_cursor: floor_the_cursor
112
+ )
113
+ puts '·' * screen_width, "\n"
114
+ puts SESSION_CLOSED_MESSAGE
115
+ puts user_named_variables_outro if current_user_named_variables.any?
116
+ end
117
+
118
+ def user_named_variables_outro
119
+ puts NAMED_VARIABLES_MESSAGE
120
+ puts current_user_named_variables.map { |s| " #{s}\n" }
121
+ end
122
+
123
+ def delete_session!(session)
124
+ scry_sessions.delete(session)
125
+ end
126
+
127
+ def session_right_of(session)
128
+ return scry_sessions.first if session == scry_sessions.last
129
+
130
+ index_of_session = scry_sessions.index(session)
131
+ scry_sessions[index_of_session + 1]
132
+ end
133
+
134
+ def session_left_of(session)
135
+ index_of_session = scry_sessions.index(session)
136
+ scry_sessions[index_of_session - 1]
137
+ end
138
+
139
+ def change_session_left!
140
+ next_session = session_left_of(current_session)
141
+ set_current_session!(next_session)
142
+ end
143
+
144
+ def change_session_right!
145
+ next_session = session_right_of(current_session)
146
+ set_current_session!(next_session)
147
+ end
148
+
149
+ def set_current_session!(session)
150
+ scry_sessions.each { |session| session.session_is_current = false }
151
+ session.session_is_current = true
152
+ end
153
+ end
154
+ end
@@ -4,6 +4,7 @@ module Scryglass
4
4
  class TreePanel < Scryglass::ViewPanel
5
5
  using ClipStringRefinement
6
6
  using AnsilessStringRefinement
7
+ using ArrayFitToRefinement
7
8
 
8
9
  def slide_view_to_cursor
9
10
  cursor_tracking = Scryglass.config.cursor_tracking
@@ -54,13 +55,37 @@ module Scryglass
54
55
 
55
56
  def uncut_header_string
56
57
  _screen_height, screen_width = $stdout.winsize
57
- header_string = "Press '?' for controls\n".rjust(screen_width, ' ') +
58
- '·' * screen_width
59
- if scry_session.special_command_targets.any?
60
- special_targets_message = " (Next command will apply to all selected rows)"
61
- header_string[0...special_targets_message.length] = special_targets_message
58
+ dotted_line = '·' * screen_width
59
+
60
+ number_to_move = scry_session.number_to_move
61
+ last_search = scry_session.last_search
62
+ special_command_targets = scry_session.special_command_targets
63
+
64
+ if special_command_targets.any?
65
+ special_targets_message = "(Next command will apply to all (#{special_command_targets.count}) selected rows)"
66
+ end
67
+ if !number_to_move.empty?
68
+ number_to_move_message = " Move distance: #{number_to_move}"
69
+ end
70
+ if last_search
71
+ last_search_message = " Last search: #{last_search}"
72
+ end
73
+ if [special_targets_message, number_to_move_message, last_search].none?
74
+ controls_key = Scryglass::Session::KEY_MAP[:control_screen]
75
+ help_key_reminder = "Press '#{controls_key}' for controls " \
76
+ "(v#{Scryglass::VERSION})"
62
77
  end
63
- header_string
78
+
79
+ tree_header_items = [
80
+ special_targets_message,
81
+ last_search_message,
82
+ number_to_move_message,
83
+ help_key_reminder
84
+ ]
85
+
86
+ fit_tree_header_array = tree_header_items.fit_to(screen_width)
87
+
88
+ fit_tree_header_array.join('') + "\n" + dotted_line
64
89
  end
65
90
 
66
91
  def visible_body_slice(uncut_body_string)
@@ -68,27 +93,29 @@ module Scryglass
68
93
 
69
94
  split_lines = uncut_body_string.split("\n")
70
95
  sliced_lines = split_lines.map do |string|
71
- ansi_length = string.length - string.ansiless.length
72
- slice_length = screen_width + ansi_length
73
- string[current_view_coords[:x], slice_length] || '' # If I don't want to
74
- # opacify here, I need to account for nils when the view is fully
75
- # beyond the shorter lines.
96
+ string.ansi_slice(current_view_coords[:x], screen_width) || '' # If I
97
+ # don't want to opacify here, I need to account for nils when the view
98
+ # is fully beyond the shorter lines.
76
99
  end
77
100
 
78
- sliced_lines.join("\n")
101
+ sliced_lines
79
102
  end
80
103
 
81
104
  def recalculate_y_boundaries
82
- self.y_boundaries = 0...scry_session.all_ros.select(&:visible?).count
105
+ number_of_lines = scry_session.all_ros.select(&:visible?).count
106
+ preview_row = 1
107
+ self.y_boundaries = 0...(number_of_lines + preview_row)
83
108
  end
84
109
 
85
110
  def recalculate_x_boundaries
86
111
  _screen_height, screen_width = $stdout.winsize
87
112
 
88
113
  split_lines = uncut_body_string.split("\n")
89
- length_of_longest_line = split_lines.map(&:length).max
114
+ length_of_longest_line = split_lines.map(&:ansiless_length).max
90
115
  max_line_length = [length_of_longest_line, screen_width].max
91
- self.x_boundaries = 0...max_line_length
116
+ preview_column = 1
117
+
118
+ self.x_boundaries = 0...(max_line_length + preview_column)
92
119
  end
93
120
 
94
121
  def top_visible_ro_of_tree_view
@@ -1,3 +1,3 @@
1
1
  module Scryglass
2
- VERSION = "0.1.0"
2
+ VERSION = "2.0.1"
3
3
  end
@@ -72,11 +72,53 @@ module Scryglass
72
72
  end
73
73
 
74
74
  def visible_body_string
75
- visible_body_slice(uncut_body_string)
75
+ _screen_height, screen_width = $stdout.winsize
76
+ screen_bottom_index = (body_screen_height - 1)
77
+ screen_right_edge_index = (screen_width - 1)
78
+
79
+ body_array = visible_body_slice(uncut_body_string)
80
+
81
+ marked_body_array =
82
+ body_array.map do |line|
83
+ last_visible_char_of_line =
84
+ line.ansiless_pick(screen_right_edge_index)
85
+
86
+ if last_visible_char_of_line
87
+ line.ansiless_set!(screen_right_edge_index, '·')
88
+ end
89
+
90
+ line
91
+ end
92
+
93
+ bottom_edge_line = marked_body_array[screen_bottom_index]
94
+
95
+ if bottom_edge_line
96
+ bottom_edge_line_has_content =
97
+ !bottom_edge_line.ansiless.tr(' ·', '').empty?
98
+
99
+ if bottom_edge_line_has_content
100
+ bottom_edge_line_dot_preview =
101
+ bottom_edge_line.ansiless.gsub(/[^\s]/, '·')
102
+ end
103
+
104
+ marked_body_array[screen_bottom_index] =
105
+ bottom_edge_line_dot_preview ||
106
+ bottom_edge_line_default_truncation_dots
107
+ end
108
+
109
+ marked_body_array.join("\n")
76
110
  end
77
111
 
78
112
  private
79
113
 
114
+ def bottom_edge_line_default_truncation_dots
115
+ _screen_height, screen_width = $stdout.winsize
116
+ dots = '· ·· ··· ·········· ··· ·· ·'
117
+ pad_length = (screen_width - dots.length) / 2
118
+
119
+ (' ' * pad_length) + dots
120
+ end
121
+
80
122
  def visible_header_slice(uncut_header_string)
81
123
  Hexes.simple_screen_slice(uncut_header_string)
82
124
  end
@@ -8,13 +8,14 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Scryglass::VERSION
9
9
  spec.authors = ["Gavin Myers"]
10
10
  spec.email = ["gavin.myers@annkissam.com"]
11
+ spec.licenses = ['MIT']
11
12
 
12
13
  spec.summary = 'Scryglass is a ruby console tool for visualizing ' \
13
14
  'and actively exploring objects.'
14
15
  spec.description = 'Scryglass is a ruby console tool for visualizing ' \
15
16
  'and actively exploring objects (large, nested, interrelated, ' \
16
17
  'or unfamiliar). You can navigate nested arrays, hashes, instance variables, ' \
17
- 'ActiveRecord relations, and unknown Enumerable types like an' \
18
+ 'ActiveRecord relations, and unknown Enumerable types like an ' \
18
19
  "expandable/collapsable file tree in an intuitive UI.\n\n" \
19
20
  'Objects and child objects can also be inspected through a variety of ' \
20
21
  'display lenses, returned directly to the console, and more!'
@@ -38,9 +39,12 @@ Gem::Specification.new do |spec|
38
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
39
40
  spec.require_paths = ["lib"]
40
41
 
41
- spec.required_ruby_version = '>= 2.4.4'
42
+ spec.required_ruby_version = '>= 2.5.3'
42
43
 
43
- spec.add_development_dependency 'activesupport', '~> 5.0'
44
44
  spec.add_development_dependency 'bundler', '~> 2.1'
45
- spec.add_development_dependency 'rake', '~> 10.0'
45
+ spec.add_development_dependency 'rake', '~> 12.0'
46
+ spec.add_development_dependency 'pry-rescue'
47
+ spec.add_runtime_dependency 'amazing_print'
48
+ spec.add_runtime_dependency 'method_source'
49
+ spec.add_runtime_dependency 'binding_of_caller'
46
50
  end
metadata CHANGED
@@ -1,59 +1,101 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scryglass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gavin Myers
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-18 00:00:00.000000000 Z
11
+ date: 2021-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: activesupport
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.1'
33
+ version: '12.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.1'
40
+ version: '12.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: pry-rescue
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: amazing_print
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: method_source
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: binding_of_caller
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
53
95
  - !ruby/object:Gem::Version
54
- version: '10.0'
96
+ version: '0'
55
97
  description: |-
56
- Scryglass is a ruby console tool for visualizing and actively exploring objects (large, nested, interrelated, or unfamiliar). You can navigate nested arrays, hashes, instance variables, ActiveRecord relations, and unknown Enumerable types like anexpandable/collapsable file tree in an intuitive UI.
98
+ Scryglass is a ruby console tool for visualizing and actively exploring objects (large, nested, interrelated, or unfamiliar). You can navigate nested arrays, hashes, instance variables, ActiveRecord relations, and unknown Enumerable types like an expandable/collapsable file tree in an intuitive UI.
57
99
 
58
100
  Objects and child objects can also be inspected through a variety of display lenses, returned directly to the console, and more!
59
101
  email:
@@ -62,8 +104,11 @@ executables: []
62
104
  extensions: []
63
105
  extra_rdoc_files: []
64
106
  files:
107
+ - ".DS_Store"
65
108
  - ".gitignore"
109
+ - ".irbrc"
66
110
  - ".tool-versions"
111
+ - CHANGELOG.md
67
112
  - Gemfile
68
113
  - Gemfile.lock
69
114
  - LICENSE.txt
@@ -80,22 +125,25 @@ files:
80
125
  - lib/refinements/clip_string_refinement.rb
81
126
  - lib/refinements/constant_defined_string_refinement.rb
82
127
  - lib/scryglass.rb
128
+ - lib/scryglass/binding_tracker.rb
83
129
  - lib/scryglass/config.rb
84
130
  - lib/scryglass/lens_helper.rb
85
131
  - lib/scryglass/lens_panel.rb
86
132
  - lib/scryglass/ro.rb
87
133
  - lib/scryglass/ro_builder.rb
88
134
  - lib/scryglass/session.rb
135
+ - lib/scryglass/session_manager.rb
89
136
  - lib/scryglass/tree_panel.rb
90
137
  - lib/scryglass/version.rb
91
138
  - lib/scryglass/view_panel.rb
92
139
  - lib/scryglass/view_wrapper.rb
93
140
  - scryglass.gemspec
94
141
  homepage: https://github.com/annkissam/scryglass
95
- licenses: []
142
+ licenses:
143
+ - MIT
96
144
  metadata:
97
145
  allowed_push_host: https://rubygems.org/
98
- post_install_message:
146
+ post_install_message:
99
147
  rdoc_options: []
100
148
  require_paths:
101
149
  - lib
@@ -103,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
151
  requirements:
104
152
  - - ">="
105
153
  - !ruby/object:Gem::Version
106
- version: 2.4.4
154
+ version: 2.5.3
107
155
  required_rubygems_version: !ruby/object:Gem::Requirement
108
156
  requirements:
109
157
  - - ">="
@@ -111,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
159
  version: '0'
112
160
  requirements: []
113
161
  rubygems_version: 3.1.4
114
- signing_key:
162
+ signing_key:
115
163
  specification_version: 4
116
164
  summary: Scryglass is a ruby console tool for visualizing and actively exploring objects.
117
165
  test_files: []