scryglass 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile.lock +1 -14
- data/README.md +17 -14
- data/example_config.rb +1 -1
- data/lib/hexes.rb +1 -1
- data/lib/refinements/ansi_slice_string_refinement.rb +65 -0
- data/lib/refinements/array_fit_to_refinement.rb +12 -0
- data/lib/scryglass.rb +5 -1
- data/lib/scryglass/lens_panel.rb +5 -5
- data/lib/scryglass/ro.rb +8 -12
- data/lib/scryglass/ro_builder.rb +2 -2
- data/lib/scryglass/session.rb +89 -46
- data/lib/scryglass/tree_panel.rb +29 -6
- data/lib/scryglass/version.rb +1 -1
- data/scryglass.gemspec +0 -1
- metadata +4 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75f5dd1ffed556a9b5d06dc18925e3c728bb2e49742fee1d7b5705c5f8be0aac
|
4
|
+
data.tar.gz: 3076092cf60d7359fc51552199584af40b23e1a71c4291ee8853738a75bc1c8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd72f233a5afe293c135ab3ed638d147397dc3400bcd37a7dc6b724f125af7484a8036ee9f1bd0fb492025ff30ee06a9c04cddb92c954912a33d7a17aa71b9f4
|
7
|
+
data.tar.gz: 3fc0b51496476cf08bc9ef79573198133265a15eeac5cac1fb573e27767aa788f1901be0887dec7dcf1341e8eedd1c0d45c12f3ddf9ba5a60f662a2b94ee0e7d
|
data/.DS_Store
ADDED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [1.1.0] - 2020-09-21
|
11
|
+
|
12
|
+
## Added
|
13
|
+
|
14
|
+
- Added ability to distinguish genuine escape key presses, and added escape key functionality.
|
15
|
+
- Added ability (AnsiSliceStringRefinement) to slice strings while effectively maintaining their ANSI formatting, as our eyes would expect.
|
16
|
+
- Added some dynamic header items to Tree View that track the following:
|
17
|
+
- Multiple targets count and message
|
18
|
+
- Last search text (what will be searched again by hitting 'n')
|
19
|
+
- Number-to-move, if digits are typed
|
20
|
+
- ('?' controls reminder now only displays when header is otherwise empty)
|
21
|
+
|
22
|
+
## Changed
|
23
|
+
|
24
|
+
- Now inputs check and screen redraws every 0.1 seconds even without user keypresses.
|
25
|
+
- (ArrayFitToRefinement now allows non-plural array counts)
|
26
|
+
|
27
|
+
## Removed
|
28
|
+
|
29
|
+
- Temporarily removed record/playback functionality
|
30
|
+
- Removed all dependency on activesupport
|
31
|
+
|
32
|
+
## Fixed
|
33
|
+
|
34
|
+
- Fixed issue where shrinking the console screen size enough would create a visual glitch until one of the boundary-resizing commands was received.
|
35
|
+
|
10
36
|
## [1.0.1] - 2020-09-18
|
11
37
|
|
12
38
|
### Added
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,17 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
scryglass (1.0
|
4
|
+
scryglass (1.1.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
activesupport (5.2.4.4)
|
10
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
-
i18n (>= 0.7, < 2)
|
12
|
-
minitest (~> 5.1)
|
13
|
-
tzinfo (~> 1.1)
|
14
|
-
concurrent-ruby (1.1.7)
|
15
|
-
i18n (1.8.5)
|
16
|
-
concurrent-ruby (~> 1.0)
|
17
|
-
minitest (5.14.2)
|
18
9
|
rake (12.3.3)
|
19
|
-
thread_safe (0.3.6)
|
20
|
-
tzinfo (1.2.7)
|
21
|
-
thread_safe (~> 0.1)
|
22
10
|
|
23
11
|
PLATFORMS
|
24
12
|
ruby
|
25
13
|
|
26
14
|
DEPENDENCIES
|
27
|
-
activesupport (~> 5.0)
|
28
15
|
bundler (~> 2.1)
|
29
16
|
rake (~> 12.0)
|
30
17
|
scryglass!
|
data/README.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
# 🔮 Scryglass
|
2
|
+
|
3
|
+
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
|
4
|
+
relations, and unknown Enumerable types like an expandable/collapsable file tree in an intuitive UI.
|
5
|
+
|
6
|
+
Objects and child objects can also be inspected through a variety of display lenses, returned directly to the console, and more!
|
7
|
+
|
8
|
+
`scry` is quick to use and useful for both experienced developers and those very new to ruby, rails, or coding.
|
9
|
+
It facilitates:
|
10
|
+
- Debugging/Investigating
|
11
|
+
- Education, learning the structure of objects and their relationships
|
12
|
+
- Comparing/Scanning sub-items in an Enumerable (e.g. Person.first.library_records.scry)
|
13
|
+
|
14
|
+
|
1
15
|
# Table of Contents
|
2
16
|
|
3
17
|
[🔮 Scryglass Intro Summary](#-scryglass)
|
@@ -18,18 +32,6 @@
|
|
18
32
|
- [Miscellaneous Troubleshooting Notes](#miscellaneous-troubleshooting-notes)
|
19
33
|
- [Contributing](#contributing)
|
20
34
|
|
21
|
-
# 🔮 Scryglass
|
22
|
-
|
23
|
-
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
|
24
|
-
relations, and unknown Enumerable types like an expandable/collapsable file tree in an intuitive UI.
|
25
|
-
|
26
|
-
Objects and child objects can also be inspected through a variety of display lenses, returned directly to the console, and more!
|
27
|
-
|
28
|
-
`scry` is quick to use and useful for both experienced developers and those very new to ruby, rails, or coding.
|
29
|
-
It facilitates:
|
30
|
-
- Debugging/Investigating
|
31
|
-
- Education, learning the structure of objects and their relationships
|
32
|
-
- Comparing/Scanning sub-items in an Enumerable (e.g. Person.first.library_records.scry)
|
33
35
|
|
34
36
|
## ⚡️ tl;dr SUPER Quick Start
|
35
37
|
|
@@ -58,7 +60,7 @@ $ gem install scryglass
|
|
58
60
|
```
|
59
61
|
## Enabling Scryglass
|
60
62
|
|
61
|
-
For the `scry` method syntax to work as cleanly as it does, Scryglass needs to add the method to the Kernel module. While this is safe, it was safest to have this only happen on a console session basis. To enable the `scry` method, call `Scryglass.load`. Thus, to automatically enable Scryglass when opening a console, you add one of the following lines to your
|
63
|
+
For the `scry` method syntax to work as cleanly as it does, Scryglass needs to add the method to the Kernel module. While this is safe, it was safest to have this only happen on a console session basis. To enable the `scry` method, call `Scryglass.load`. Thus, to automatically enable Scryglass when opening a console, you add one of the following lines to your `./.irbrc` (and `./.pryrc` for rails or pry sessions):
|
62
64
|
```ruby
|
63
65
|
Scryglass.load
|
64
66
|
```
|
@@ -162,6 +164,7 @@ Scryglass has two features to make wait time a little easier:
|
|
162
164
|
| `-` | Select/Deselect current row | If these objects are later returned, the order in which they were selected will determine their order in the returned array. |
|
163
165
|
| `/` | Begin a text search (in tree view) | Begins a case-sensitive regex search of all items, in a loop, starting with just below the current row. For a matching object to be found, the search must match its *truncated sample string in tree view* (regardless of what is on or off screen) (it must match either the key or the value, not the full line they create) (known enumerable types, like `[•••]`, may count as a match if they contain the string in the backend). |
|
164
166
|
| `n` | Move to next search result | Will, using the most recent search entry, move the cursor on to the next match downward, cycling through all rows. This follows the same matching rules as the original search. |
|
167
|
+
| `Esc` | Resets selection, last search, and number-to-move. (or returns to Tree View) | (Essentially, clears the values represented in the Tree View header if you're in the Tree View; otherwise it returns you to the Tree View) |
|
165
168
|
|
166
169
|
## Configuration / Customization (all optional)
|
167
170
|
|
@@ -192,7 +195,7 @@ Scryglass.configure do |config|
|
|
192
195
|
# { name: 'Inspect (`.inspect`)',
|
193
196
|
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o.inspect } } },
|
194
197
|
# { name: 'Yaml Print (`y`)',
|
195
|
-
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { y o } } }, # OR: `puts o.to_yaml`
|
198
|
+
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { require 'yaml' ; y o } } }, # OR: `puts o.to_yaml`
|
196
199
|
# { name: 'Puts (`puts`)',
|
197
200
|
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o } } },
|
198
201
|
# # { name: 'Method Showcase', # Not included by default
|
data/example_config.rb
CHANGED
@@ -15,7 +15,7 @@ Scryglass.configure do |config|
|
|
15
15
|
# { name: 'Inspect (`.inspect`)',
|
16
16
|
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o.inspect } } },
|
17
17
|
# { name: 'Yaml Print (`y`)',
|
18
|
-
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { y o } } }, # OR: `puts o.to_yaml`
|
18
|
+
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { require 'yaml' ; y o } } }, # OR: `puts o.to_yaml`
|
19
19
|
# { name: 'Puts (`puts`)',
|
20
20
|
# lambda: ->(o) { Hexes.capture_io(char_limit: 20_000) { puts o } } },
|
21
21
|
# # { name: 'Method Showcase', # Not included by default
|
data/lib/hexes.rb
CHANGED
@@ -107,7 +107,7 @@ module Hexes
|
|
107
107
|
necessary_constants_defined = necessary_constants.all?(&:constant_defined?)
|
108
108
|
return yield unless necessary_constants_defined
|
109
109
|
|
110
|
-
rails_logger_defined = 'Rails'.constant_defined? && Rails.try(:logger)
|
110
|
+
rails_logger_defined = 'Rails'.constant_defined? && !!Rails.try(:logger)
|
111
111
|
|
112
112
|
## These are purposefully preserved as global variables so retrieval, in
|
113
113
|
## debugging or errored usage, is as easy as possible.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module AnsiSliceStringRefinement
|
3
|
+
refine String do
|
4
|
+
## (This really might not do what you expect if your string has (or you are
|
5
|
+
## printing) unescaped newlines).
|
6
|
+
def ansi_slice(target_range)
|
7
|
+
unless target_range.is_a?(Range)
|
8
|
+
raise ArgumentError, 'ansi_slice takes a Range as its argument!'
|
9
|
+
end
|
10
|
+
if target_range.min.negative? || target_range.max.negative?
|
11
|
+
raise ArgumentError, 'Range argument must be entirely positive!'
|
12
|
+
end
|
13
|
+
|
14
|
+
return self[target_range] if (self =~ /\e\[[\d\;]*m/).nil? # Just quick
|
15
|
+
|
16
|
+
mock_index = 0 # A scanning index that *doesn't* count ANSI codes
|
17
|
+
result_string_array = []
|
18
|
+
|
19
|
+
ansi_string_breakout.each do |char|
|
20
|
+
char_is_ansi_escape_code = char.is_ansi_escape_code?
|
21
|
+
within_target_range =
|
22
|
+
target_range.include?(mock_index)
|
23
|
+
# char_is_applicable_ansi_code =
|
24
|
+
# (char_is_ansi_escape_code && mock_index <= target_range.max)
|
25
|
+
|
26
|
+
if within_target_range || char_is_ansi_escape_code
|
27
|
+
result_string_array << char
|
28
|
+
end
|
29
|
+
|
30
|
+
mock_index += 1 unless char_is_ansi_escape_code
|
31
|
+
end
|
32
|
+
|
33
|
+
result_string_array.join('')
|
34
|
+
end
|
35
|
+
|
36
|
+
## Splits string into characters, with each ANSI escape code being its own
|
37
|
+
## grouped item, like so:
|
38
|
+
## irb> "PLAIN\e[32mCOLOR\e[0mPLAIN".ansi_string_breakout
|
39
|
+
## => ["P", "L", "A", "I", "N", "\e[32m", "C", "O", "L", "O", "R",
|
40
|
+
## "\e[0m", "P", "L", "A", "I", "N"]
|
41
|
+
def ansi_string_breakout
|
42
|
+
breakout_array = []
|
43
|
+
working_self = self.dup
|
44
|
+
|
45
|
+
while working_self[0]
|
46
|
+
if (working_self =~ /\e\[[\d\;]*m/) == 0 # if begins with
|
47
|
+
end_of_escape_code = (working_self.index('m'))
|
48
|
+
leading_escape_code = working_self[0..end_of_escape_code]
|
49
|
+
breakout_array << leading_escape_code
|
50
|
+
working_self = working_self[(end_of_escape_code + 1)..-1]
|
51
|
+
else
|
52
|
+
leading_character = working_self[0]
|
53
|
+
breakout_array << leading_character
|
54
|
+
working_self = working_self[1..-1]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
breakout_array
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_ansi_escape_code?
|
62
|
+
(self =~ /^\e\[[\d\;]*m$/) == 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -8,6 +8,9 @@ module ArrayFitToRefinement
|
|
8
8
|
length_method = ignore_ansi_codes ? :ansiless_length : :length
|
9
9
|
length_result = string_array.join('').send(length_method)
|
10
10
|
|
11
|
+
if string_array.count < 2
|
12
|
+
return nonplural_solution(string_length_goal, length_result, fill: fill)
|
13
|
+
end
|
11
14
|
|
12
15
|
if length_result > string_length_goal
|
13
16
|
string_array.compress_to(string_length_goal, ignore_ansi_codes: ignore_ansi_codes)
|
@@ -63,5 +66,14 @@ module ArrayFitToRefinement
|
|
63
66
|
|
64
67
|
working_array.zip(spacers).flatten.compact
|
65
68
|
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def nonplural_solution(string_length_goal, length_result, fill:)
|
73
|
+
return [fill * string_length_goal] if self.empty?
|
74
|
+
|
75
|
+
remaining_space = string_length_goal - length_result
|
76
|
+
return self.map(&:to_s).append(fill * remaining_space)
|
77
|
+
end
|
66
78
|
end
|
67
79
|
end
|
data/lib/scryglass.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'stringio'
|
3
|
+
|
3
4
|
## Bookkeeping and external tools:
|
4
5
|
require "scryglass/version"
|
5
|
-
require 'active_support/core_ext/object/blank' # This gives us `.present?` and `.blank?` # https://stackoverflow.com/questions/4648684/how-to-use-present-in-ruby-projects
|
6
6
|
require 'io/console'
|
7
7
|
require 'pp'
|
8
|
+
require 'timeout'
|
8
9
|
|
9
10
|
## Refinements and sub-tools:
|
10
11
|
require 'refinements/ansiless_string_refinement'
|
12
|
+
# require 'refinements/ansi_slice_string_refinement' # Employed soon
|
11
13
|
require 'refinements/clip_string_refinement'
|
12
14
|
require 'refinements/constant_defined_string_refinement'
|
13
15
|
require 'refinements/array_fit_to_refinement'
|
@@ -76,6 +78,8 @@ module Scryglass
|
|
76
78
|
· / : Begin a text search (in tree view) ·
|
77
79
|
· n : Move to next search result ·
|
78
80
|
· ·
|
81
|
+
· Esc : Resets selection, last search, and number-to-move. (or returns to Tree View) ·
|
82
|
+
· ·
|
79
83
|
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
|
80
84
|
HELPSCREENADVANCEDPAGE
|
81
85
|
|
data/lib/scryglass/lens_panel.rb
CHANGED
@@ -78,7 +78,7 @@ module Scryglass
|
|
78
78
|
|
79
79
|
def current_ro_subheader
|
80
80
|
current_ro = scry_session.current_ro
|
81
|
-
|
81
|
+
last_keypress = scry_session.last_keypress
|
82
82
|
|
83
83
|
row_above_string =
|
84
84
|
current_ro.next_visible_ro_up.to_s if current_ro.next_visible_ro_up
|
@@ -88,7 +88,7 @@ module Scryglass
|
|
88
88
|
tree_preview_related_commands = ['A', 'B', 'C', 'D',
|
89
89
|
'@', '.', '(', '*', '|', '-']
|
90
90
|
ro_view_label =
|
91
|
-
if tree_preview_related_commands.include?(
|
91
|
+
if tree_preview_related_commands.include?(last_keypress)
|
92
92
|
"\e[7mVIEWING:\e[00m" # Color reversed
|
93
93
|
else
|
94
94
|
'VIEWING:'
|
@@ -108,7 +108,7 @@ module Scryglass
|
|
108
108
|
current_lens = scry_session.current_lens
|
109
109
|
current_subject_type = scry_session.current_subject_type
|
110
110
|
current_subject = scry_session.current_ro.current_subject
|
111
|
-
|
111
|
+
last_keypress = scry_session.last_keypress
|
112
112
|
|
113
113
|
lens_count = LensPanel.lenses.count
|
114
114
|
lens_id = current_lens % lens_count
|
@@ -128,9 +128,9 @@ module Scryglass
|
|
128
128
|
subject_type_header, subject_class_header, lens_type_header
|
129
129
|
].fit_to(screen_width)
|
130
130
|
|
131
|
-
if
|
131
|
+
if last_keypress == 'l'
|
132
132
|
fit_lens_header[4] = "\e[7m#{fit_lens_header[4]}" # Format to be ended by Hexes.opacify_screen_string() (using \e[00m)
|
133
|
-
elsif
|
133
|
+
elsif last_keypress == 'L'
|
134
134
|
fit_lens_header[0] = "\e[7m#{fit_lens_header[0]}\e[00m"
|
135
135
|
end
|
136
136
|
|
data/lib/scryglass/ro.rb
CHANGED
@@ -114,19 +114,15 @@ module Scryglass
|
|
114
114
|
|
115
115
|
# (Used for recalculate_indeces after new Ros have been injected)
|
116
116
|
def next_ro_without_using_index
|
117
|
-
if sub_ros.
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
upward_feeler_ro = self
|
125
|
-
until upward_feeler_ro.sibling_down.present? || upward_feeler_ro.top_ro?
|
126
|
-
upward_feeler_ro = upward_feeler_ro.parent_ro
|
127
|
-
end
|
128
|
-
upward_feeler_ro.sibling_down
|
117
|
+
return sub_ros.first if sub_ros.first
|
118
|
+
return nil if top_ro?
|
119
|
+
return sibling_down if sibling_down
|
120
|
+
|
121
|
+
upward_feeler_ro = self
|
122
|
+
until upward_feeler_ro.sibling_down || upward_feeler_ro.top_ro?
|
123
|
+
upward_feeler_ro = upward_feeler_ro.parent_ro
|
129
124
|
end
|
125
|
+
upward_feeler_ro.sibling_down
|
130
126
|
end
|
131
127
|
|
132
128
|
def sibling_down
|
data/lib/scryglass/ro_builder.rb
CHANGED
@@ -310,7 +310,7 @@ module Scryglass
|
|
310
310
|
through_indicator = is_through ? '(t)' : ' '
|
311
311
|
end
|
312
312
|
|
313
|
-
is_scoped = info.scope
|
313
|
+
is_scoped = !!info.scope
|
314
314
|
if include_scoped_associations
|
315
315
|
scoped_indicator = is_scoped ? '(s)' : ' '
|
316
316
|
end
|
@@ -322,7 +322,7 @@ module Scryglass
|
|
322
322
|
relation_name.to_s
|
323
323
|
end
|
324
324
|
|
325
|
-
if ar_value.
|
325
|
+
if (!ar_value || ar_value.empty?) || include_empty_associations
|
326
326
|
ar_key = Scryglass::ViewWrapper.new(
|
327
327
|
relation_name,
|
328
328
|
string: relation_representation
|
data/lib/scryglass/session.rb
CHANGED
@@ -11,7 +11,7 @@ class Scryglass::Session
|
|
11
11
|
:view_panels, :current_panel_type,
|
12
12
|
:progress_bar
|
13
13
|
|
14
|
-
attr_accessor :
|
14
|
+
attr_accessor :user_signals, :last_search, :number_to_move
|
15
15
|
|
16
16
|
CURSOR_CHARACTER = '–' # These are en dashes (alt+dash), not hyphens or em dashes.
|
17
17
|
|
@@ -33,7 +33,7 @@ class Scryglass::Session
|
|
33
33
|
self.current_panel_type = :tree
|
34
34
|
self.special_command_targets = []
|
35
35
|
self.number_to_move = ''
|
36
|
-
self.
|
36
|
+
self.user_signals = []
|
37
37
|
self.progress_bar = Prog::Pipe.new
|
38
38
|
|
39
39
|
top_ro = roify(seed, parent_ro: nil, depth: 1)
|
@@ -52,15 +52,16 @@ class Scryglass::Session
|
|
52
52
|
in_scry_session = true
|
53
53
|
redraw = true
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
55
|
+
## On hold: Record/Playback Functionality:
|
56
|
+
# case actions
|
57
|
+
# when :record
|
58
|
+
# $scry_session_actions_performed = []
|
59
|
+
# when :playback
|
60
|
+
# if $scry_session_actions_performed.blank?
|
61
|
+
# raise 'Could not find recording of previous session\'s actions'
|
62
|
+
# end
|
63
|
+
# @input_stack = $scry_session_actions_performed.dup
|
64
|
+
# end
|
64
65
|
|
65
66
|
# We print a full screen of lines so the first call of draw_screen doesn't
|
66
67
|
# write over any previous valuable content the user had in the console.
|
@@ -70,24 +71,35 @@ class Scryglass::Session
|
|
70
71
|
draw_screen if redraw
|
71
72
|
redraw = true
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
74
|
+
## On hold: Record/Playback Functionality:
|
75
|
+
# case actions
|
76
|
+
# when :record
|
77
|
+
# self.user_input = $stdin.getch
|
78
|
+
# $scry_session_actions_performed << user_input
|
79
|
+
# when :playback
|
80
|
+
# if @input_stack.any? # (IV to be easily accessible for debugging)
|
81
|
+
# self.user_input = @input_stack.shift
|
82
|
+
# sleep 0.05
|
83
|
+
# else
|
84
|
+
# self.user_input = $stdin.getch
|
85
|
+
# end
|
86
|
+
# else
|
87
|
+
# self.user_input = $stdin.getch
|
88
|
+
# end
|
89
|
+
|
90
|
+
new_signal = fetch_user_signal
|
87
91
|
|
88
92
|
wait_start_time = Time.now
|
89
93
|
|
90
|
-
case
|
94
|
+
case new_signal
|
95
|
+
when nil
|
96
|
+
when 'esc'
|
97
|
+
case current_panel_type
|
98
|
+
when :lens
|
99
|
+
self.current_panel_type = :tree
|
100
|
+
when :tree
|
101
|
+
clear_tracked_values
|
102
|
+
end
|
91
103
|
when "\u0003"
|
92
104
|
set_console_cursor_below_content
|
93
105
|
raise IRB::Abort, 'Ctrl+C Detected'
|
@@ -123,40 +135,34 @@ class Scryglass::Session
|
|
123
135
|
self.number_to_move += '9'
|
124
136
|
redraw = false
|
125
137
|
when '0'
|
126
|
-
if number_to_move
|
138
|
+
if number_to_move[0] # You can append zeros to existing number_to_move...
|
127
139
|
self.number_to_move += '0'
|
128
140
|
redraw = false
|
129
141
|
else # ...but otherwise it's understood to be a view||cursor reset.
|
130
142
|
reset_the_view_or_cursor
|
131
143
|
end
|
132
144
|
when 'A' # Up arrow
|
133
|
-
action_count = number_to_move.
|
145
|
+
action_count = !number_to_move.empty? ? number_to_move.to_i : 1
|
134
146
|
navigate_up_multiple(action_count)
|
135
147
|
|
136
148
|
self.number_to_move = ''
|
137
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
138
149
|
tree_view.slide_view_to_cursor
|
139
150
|
when 'B' # Down arrow
|
140
|
-
action_count = number_to_move.
|
151
|
+
action_count = !number_to_move.empty? ? number_to_move.to_i : 1
|
141
152
|
navigate_down_multiple(action_count)
|
142
153
|
|
143
154
|
self.number_to_move = ''
|
144
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
145
155
|
tree_view.slide_view_to_cursor
|
146
156
|
when 'C' # Right arrow
|
147
157
|
expand_targets
|
148
158
|
when 'D' # Left arrow
|
149
159
|
collapse_targets
|
150
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
151
160
|
when ' '
|
152
161
|
toggle_view_panel
|
153
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
154
162
|
when 'l'
|
155
163
|
scroll_lens_type
|
156
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
157
164
|
when 'L'
|
158
165
|
toggle_current_subject_type
|
159
|
-
lens_view.recalculate_boundaries if current_panel_type == :lens
|
160
166
|
when 'w'
|
161
167
|
current_view_panel.move_view_up(5)
|
162
168
|
when 's'
|
@@ -177,15 +183,12 @@ class Scryglass::Session
|
|
177
183
|
in_scry_session = run_help_screen_ui
|
178
184
|
when '@'
|
179
185
|
build_instance_variables_for_target_ros
|
180
|
-
tree_view.recalculate_boundaries
|
181
186
|
tree_view.slide_view_to_cursor # Just a nice-to-have
|
182
187
|
when '.'
|
183
188
|
build_activerecord_relations_for_target_ros
|
184
|
-
tree_view.recalculate_boundaries
|
185
189
|
tree_view.slide_view_to_cursor # Just a nice-to-have
|
186
190
|
when '('
|
187
191
|
build_enum_children_for_target_ros
|
188
|
-
tree_view.recalculate_boundaries
|
189
192
|
tree_view.slide_view_to_cursor # Just a nice-to-have
|
190
193
|
when '|'
|
191
194
|
sibling_ros = if current_ro.top_ro?
|
@@ -214,12 +217,15 @@ class Scryglass::Session
|
|
214
217
|
special_command_targets << current_ro
|
215
218
|
end
|
216
219
|
when '/'
|
220
|
+
_screen_height, screen_width = $stdout.winsize
|
217
221
|
$stdout.write "#{CSI}1;1H" # (Moves console cursor to top left corner)
|
218
|
-
$stdout.
|
222
|
+
$stdout.print ' ' * screen_width
|
223
|
+
$stdout.write "#{CSI}1;1H" # (Moves console cursor to top left corner)
|
224
|
+
$stdout.print SEARCH_PROMPT
|
219
225
|
$stdout.write "#{CSI}1;#{SEARCH_PROMPT.ansiless_length + 1}H" # (Moves
|
220
226
|
# console cursor to just after the search prompt, before user types)
|
221
227
|
query = $stdin.gets.chomp
|
222
|
-
|
228
|
+
unless query.empty?
|
223
229
|
self.last_search = query
|
224
230
|
go_to_next_search_result
|
225
231
|
end
|
@@ -236,7 +242,7 @@ class Scryglass::Session
|
|
236
242
|
return subjects_of_target_ros
|
237
243
|
end
|
238
244
|
|
239
|
-
print "\a" if Time.now - wait_start_time > 4 &&
|
245
|
+
print "\a" if Time.now - wait_start_time > 4 && last_keypress != '?' # (Audio 'beep')
|
240
246
|
end
|
241
247
|
end
|
242
248
|
|
@@ -244,13 +250,24 @@ class Scryglass::Session
|
|
244
250
|
all_ros.first
|
245
251
|
end
|
246
252
|
|
253
|
+
def last_keypress
|
254
|
+
last_two_signals = user_signals.last(2)
|
255
|
+
last_two_signals.last || last_two_signals.first
|
256
|
+
end
|
257
|
+
|
247
258
|
private
|
248
259
|
|
260
|
+
def clear_tracked_values
|
261
|
+
self.special_command_targets = []
|
262
|
+
self.last_search = nil
|
263
|
+
self.number_to_move = ''
|
264
|
+
end
|
265
|
+
|
249
266
|
def print_progress_bar
|
250
267
|
screen_height, _screen_width = $stdout.winsize
|
251
268
|
bar = progress_bar.to_s
|
252
269
|
$stdout.write "#{CSI}#{screen_height};1H" # (Moves console cursor to bottom left corner)
|
253
|
-
print bar
|
270
|
+
print bar unless bar.tr(' ', '').empty?
|
254
271
|
end
|
255
272
|
|
256
273
|
def current_view_panel
|
@@ -325,6 +342,29 @@ class Scryglass::Session
|
|
325
342
|
end
|
326
343
|
end
|
327
344
|
|
345
|
+
def fetch_user_signal
|
346
|
+
previous_signal = user_signals.last
|
347
|
+
new_signal =
|
348
|
+
begin
|
349
|
+
Timeout.timeout(0.1) { $stdin.getch }
|
350
|
+
rescue Timeout::Error
|
351
|
+
nil
|
352
|
+
end
|
353
|
+
|
354
|
+
## Since many keys, including arrow keys, result in several signals being
|
355
|
+
## sent (e.g. DOWN: "\e" then "[" then "B" in RAPID succession), the
|
356
|
+
## *pause* after a genuine escape key press (also "\e") is the only way
|
357
|
+
## to distinguish it precisely.
|
358
|
+
genuine_escape_key_press = new_signal.nil? && previous_signal == "\e"
|
359
|
+
if genuine_escape_key_press
|
360
|
+
new_signal = 'esc'
|
361
|
+
end
|
362
|
+
|
363
|
+
user_signals << new_signal unless new_signal.nil? && previous_signal.nil?
|
364
|
+
|
365
|
+
new_signal
|
366
|
+
end
|
367
|
+
|
328
368
|
def run_help_screen_ui
|
329
369
|
screen_height, _screen_width = $stdout.winsize
|
330
370
|
|
@@ -337,9 +377,12 @@ class Scryglass::Session
|
|
337
377
|
sliced_help_screen = Hexes.simple_screen_slice(current_help_screen)
|
338
378
|
help_screen_string = Hexes.opacify_screen_string(sliced_help_screen)
|
339
379
|
Hexes.overwrite_screen(help_screen_string)
|
340
|
-
help_screen_user_input = $stdin.getch
|
341
380
|
|
342
|
-
|
381
|
+
new_signal = fetch_user_signal
|
382
|
+
|
383
|
+
case new_signal
|
384
|
+
when 'esc'
|
385
|
+
return true
|
343
386
|
when '?'
|
344
387
|
current_help_screen_index += 1
|
345
388
|
when 'q'
|
@@ -375,7 +418,6 @@ class Scryglass::Session
|
|
375
418
|
|
376
419
|
move_cursor_to(current_ro.parent_ro) until current_ro.visible?
|
377
420
|
tree_view.slide_view_to_cursor
|
378
|
-
tree_view.recalculate_boundaries # TODO: should these be conditional? If they are, I might need a potential tree view recalc after toggling lens view to tree view.
|
379
421
|
end
|
380
422
|
|
381
423
|
def expand_targets
|
@@ -388,7 +430,6 @@ class Scryglass::Session
|
|
388
430
|
else
|
389
431
|
expand!(current_ro)
|
390
432
|
end
|
391
|
-
tree_view.recalculate_boundaries
|
392
433
|
end
|
393
434
|
|
394
435
|
def reset_the_view_or_cursor
|
@@ -400,6 +441,8 @@ class Scryglass::Session
|
|
400
441
|
end
|
401
442
|
|
402
443
|
def draw_screen
|
444
|
+
current_view_panel.recalculate_boundaries # This now happens at every screen
|
445
|
+
# draw to account for the user changing the screen size. Otherwise glitch.
|
403
446
|
current_view_panel.ensure_correct_view_coords
|
404
447
|
screen_string = current_view_panel.screen_string
|
405
448
|
|
data/lib/scryglass/tree_panel.rb
CHANGED
@@ -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,35 @@ module Scryglass
|
|
54
55
|
|
55
56
|
def uncut_header_string
|
56
57
|
_screen_height, screen_width = $stdout.winsize
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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}"
|
62
72
|
end
|
63
|
-
|
73
|
+
if [special_targets_message, number_to_move_message, last_search].none?
|
74
|
+
help_key_reminder = "Press '?' for controls"
|
75
|
+
end
|
76
|
+
|
77
|
+
tree_header_items = [
|
78
|
+
special_targets_message,
|
79
|
+
last_search_message,
|
80
|
+
number_to_move_message,
|
81
|
+
help_key_reminder
|
82
|
+
]
|
83
|
+
|
84
|
+
fit_tree_header_array = tree_header_items.fit_to(screen_width)
|
85
|
+
|
86
|
+
fit_tree_header_array.join('') + "\n" + dotted_line
|
64
87
|
end
|
65
88
|
|
66
89
|
def visible_body_slice(uncut_body_string)
|
data/lib/scryglass/version.rb
CHANGED
data/scryglass.gemspec
CHANGED
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scryglass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gavin Myers
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '5.0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '5.0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,6 +48,7 @@ executables: []
|
|
62
48
|
extensions: []
|
63
49
|
extra_rdoc_files: []
|
64
50
|
files:
|
51
|
+
- ".DS_Store"
|
65
52
|
- ".gitignore"
|
66
53
|
- ".tool-versions"
|
67
54
|
- CHANGELOG.md
|
@@ -76,6 +63,7 @@ files:
|
|
76
63
|
- lib/example_material.rb
|
77
64
|
- lib/hexes.rb
|
78
65
|
- lib/prog.rb
|
66
|
+
- lib/refinements/ansi_slice_string_refinement.rb
|
79
67
|
- lib/refinements/ansiless_string_refinement.rb
|
80
68
|
- lib/refinements/array_fit_to_refinement.rb
|
81
69
|
- lib/refinements/clip_string_refinement.rb
|