remedy 0.3.1 → 0.5.0
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/workflows/ci.yml +1 -1
- data/README.markdown +1 -1
- data/examples/from_readme/Gemfile +3 -0
- data/examples/menu/Gemfile +3 -0
- data/examples/menu/menu.rb +3 -8
- data/lib/remedy/console.rb +16 -2
- data/lib/remedy/console_resize.rb +1 -0
- data/lib/remedy/interaction.rb +1 -1
- data/lib/remedy/partial.rb +5 -3
- data/lib/remedy/size.rb +7 -1
- data/lib/remedy/version.rb +1 -1
- data/lib/remedy/viewport.rb +28 -23
- data/remedy.gemspec +3 -0
- data/spec/viewport_spec.rb +24 -3
- metadata +19 -4
- data/.travis.yml +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a8fe8ed0c57993d0c71fa5d584dce0343e6548d4b42ce70431333fb62d9490d
|
4
|
+
data.tar.gz: 0eab58e635c11d57b167d842ce6411d4970ac9d4a4adb4660b057a4ae2d7b217
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4206bd86137641bea396f02d9935488e7b099c65515d41312e372f9ad8dc0c80d8352190049a92907f2c6db78e0a1a438fa7743a418ee5cdcfe59612e2cafcb2
|
7
|
+
data.tar.gz: 9f4d5f519809aa4d2c720358f82c888657235781d4713ba705a35331e3ad6c24396b0031b05cae74d5cfef0c1996e8a56180766b363fd473aa42fcd90cc6cc7f
|
data/.github/workflows/ci.yml
CHANGED
@@ -10,7 +10,7 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
fail-fast: false
|
12
12
|
matrix:
|
13
|
-
ruby: ["2.
|
13
|
+
ruby: ["2.5", "2.6", "2.7", "3.0", "3.1", "3.2", "3.3", "3.4", ruby-head, jruby-10.0, jruby-head]
|
14
14
|
|
15
15
|
steps:
|
16
16
|
- uses: actions/checkout@v4
|
data/README.markdown
CHANGED
@@ -110,7 +110,7 @@ The most interesting function in my opinion is the callback that gets triggered
|
|
110
110
|
Remedy in the Wild
|
111
111
|
------------------
|
112
112
|
|
113
|
-
Remedy was originally written for my own console-based game
|
113
|
+
Remedy was originally written for my own console-based game. Remedy was extracted from it and open-sourced and it has lived on.
|
114
114
|
|
115
115
|
Here are some projects that use Remedy:
|
116
116
|
|
data/examples/menu/menu.rb
CHANGED
@@ -11,11 +11,6 @@ class Menu
|
|
11
11
|
|
12
12
|
# will do basic setup and then loop over user input
|
13
13
|
def listen
|
14
|
-
# get the screen in a reliable state and clear it
|
15
|
-
ANSI.screen.safe_reset!
|
16
|
-
ANSI.cursor.home!
|
17
|
-
ANSI.command.clear_screen!
|
18
|
-
|
19
14
|
# if the user resizes the screen we redraw it to fit the new dimensions
|
20
15
|
Console.set_console_resized_hook! do |size|
|
21
16
|
draw
|
@@ -24,10 +19,10 @@ class Menu
|
|
24
19
|
# create an interaction object to handle user input
|
25
20
|
interaction = Interaction.new
|
26
21
|
|
27
|
-
# call draw here because interaction blocks until it gets input
|
22
|
+
# call draw here because the interaction loop blocks until it gets input
|
28
23
|
draw
|
29
24
|
|
30
|
-
# loop over
|
25
|
+
# loop over individual keypresses or ANSI codes from the terminal
|
31
26
|
interaction.loop do |key|
|
32
27
|
@last_key = key
|
33
28
|
if key == "q" then
|
@@ -39,7 +34,7 @@ class Menu
|
|
39
34
|
|
40
35
|
# this tells the Viewport to draw to the screen
|
41
36
|
def draw
|
42
|
-
@viewport.draw content, Size
|
37
|
+
@viewport.draw content, Size.zero, header, footer
|
43
38
|
end
|
44
39
|
|
45
40
|
# this is the body of our menu, it will be squished if the terminal is too small
|
data/lib/remedy/console.rb
CHANGED
@@ -23,6 +23,14 @@ module Remedy
|
|
23
23
|
@output ||= $stdout
|
24
24
|
end
|
25
25
|
|
26
|
+
def input= new_input
|
27
|
+
@input = new_input
|
28
|
+
end
|
29
|
+
|
30
|
+
def output= new_output
|
31
|
+
@output = new_output
|
32
|
+
end
|
33
|
+
|
26
34
|
def raw
|
27
35
|
raw!
|
28
36
|
result = yield
|
@@ -52,21 +60,27 @@ module Remedy
|
|
52
60
|
alias_method :height, :rows
|
53
61
|
|
54
62
|
def size
|
63
|
+
return @size_override if @size_override
|
64
|
+
|
55
65
|
str = [0, 0, 0, 0].pack('SSSS')
|
56
|
-
if input.ioctl(TIOCGWINSZ, str) >= 0 then
|
66
|
+
if input.respond_to?(:ioctl) && input.ioctl(TIOCGWINSZ, str) >= 0 then
|
57
67
|
Size.new str.unpack('SSSS').first 2
|
58
68
|
else
|
59
69
|
raise UnknownConsoleSize, "Unable to get console size"
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
73
|
+
def size_override= new_size
|
74
|
+
@size_override = new_size
|
75
|
+
end
|
76
|
+
|
63
77
|
def interactive?
|
64
78
|
input.isatty
|
65
79
|
end
|
66
80
|
|
67
81
|
def set_console_resized_hook!
|
68
82
|
Console::Resize.set_console_resized_hook! do |*args|
|
69
|
-
yield
|
83
|
+
yield(*args)
|
70
84
|
end
|
71
85
|
end
|
72
86
|
|
data/lib/remedy/interaction.rb
CHANGED
data/lib/remedy/partial.rb
CHANGED
@@ -16,6 +16,7 @@ module Remedy
|
|
16
16
|
reset_width!
|
17
17
|
line = "#{line}" # opportunistically convert any object into a string
|
18
18
|
@lines += clean line unless line.nil? || line.empty?
|
19
|
+
self
|
19
20
|
end
|
20
21
|
|
21
22
|
def first
|
@@ -26,16 +27,17 @@ module Remedy
|
|
26
27
|
lines.last
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
+
def height
|
30
31
|
lines.length
|
31
32
|
end
|
33
|
+
alias_method :length, :height
|
32
34
|
|
33
35
|
def width
|
34
|
-
|
36
|
+
lines.map{|line| line.length }.max || 0
|
35
37
|
end
|
36
38
|
|
37
39
|
def size
|
38
|
-
Size.new
|
40
|
+
Size.new height, width
|
39
41
|
end
|
40
42
|
|
41
43
|
def to_a
|
data/lib/remedy/size.rb
CHANGED
@@ -11,6 +11,10 @@ module Remedy
|
|
11
11
|
end
|
12
12
|
attr_accessor :dimensions
|
13
13
|
|
14
|
+
def self.zero
|
15
|
+
self.new([0,0])
|
16
|
+
end
|
17
|
+
|
14
18
|
def - other_size
|
15
19
|
if other_size.respond_to? :length then
|
16
20
|
self.class.new subtract(other_size)
|
@@ -41,11 +45,13 @@ module Remedy
|
|
41
45
|
def rows
|
42
46
|
dimensions[0]
|
43
47
|
end
|
48
|
+
alias_method :height, :rows
|
44
49
|
|
45
50
|
def cols
|
46
51
|
dimensions[1]
|
47
52
|
end
|
48
|
-
|
53
|
+
alias_method :columns, :cols
|
54
|
+
alias_method :width, :cols
|
49
55
|
|
50
56
|
def [] index
|
51
57
|
dimensions[index]
|
data/lib/remedy/version.rb
CHANGED
data/lib/remedy/viewport.rb
CHANGED
@@ -5,14 +5,10 @@ require 'remedy/ansi'
|
|
5
5
|
|
6
6
|
module Remedy
|
7
7
|
class Viewport
|
8
|
-
def draw content,
|
9
|
-
range = range_find content,
|
8
|
+
def draw content, scroll = Size.zero, header = Partial.new, footer = Partial.new
|
9
|
+
range = range_find content, scroll, available_space(header,footer)
|
10
10
|
|
11
|
-
|
12
|
-
viewable_content = content
|
13
|
-
else
|
14
|
-
viewable_content = content.excerpt *range
|
15
|
-
end
|
11
|
+
viewable_content = content.excerpt(*range)
|
16
12
|
|
17
13
|
view = View.new viewable_content, header, footer
|
18
14
|
|
@@ -20,40 +16,49 @@ module Remedy
|
|
20
16
|
Console.output << view
|
21
17
|
end
|
22
18
|
|
23
|
-
def range_find partial,
|
24
|
-
|
25
|
-
|
19
|
+
def range_find partial, scroll, available_heightwidth
|
20
|
+
avail_height, avail_width = available_heightwidth
|
21
|
+
partial_height, partial_width = partial.size
|
22
|
+
|
23
|
+
center_row, center_col = scroll
|
26
24
|
|
27
|
-
center_row,
|
25
|
+
row_range = get_range center_row, partial_height, avail_height
|
26
|
+
col_range = get_range center_col, partial_width, avail_width
|
28
27
|
|
29
|
-
row_range = center_range center_row, row_size, row_limit
|
30
|
-
col_range = center_range center_col, col_size, col_limit
|
31
28
|
[row_range, col_range]
|
32
29
|
end
|
33
30
|
|
34
|
-
|
35
|
-
|
31
|
+
# This determines the maximum amount of room left available for Content
|
32
|
+
# after taking into consideration the height of the Header and Footer
|
33
|
+
def available_space header, footer
|
34
|
+
trim = Size [header.height + footer.height, 0]
|
36
35
|
size - trim
|
37
36
|
end
|
38
37
|
|
39
38
|
def size
|
40
|
-
|
39
|
+
Console.size
|
41
40
|
end
|
42
41
|
|
43
|
-
def
|
44
|
-
|
42
|
+
def get_range offset, actual, available
|
43
|
+
# if the actual content can fit into the available space, then we're done
|
44
|
+
return (0...actual) if actual <= available
|
45
45
|
|
46
|
-
|
47
|
-
range_start = limit - width
|
48
|
-
end
|
46
|
+
# otherwise start looking at the scrolling offset, if any
|
49
47
|
|
50
|
-
|
48
|
+
# clamp the offset within the possible range of the actual content
|
49
|
+
if offset < 0 then
|
51
50
|
range_start = 0
|
51
|
+
elsif offset > actual then
|
52
|
+
range_start = actual
|
53
|
+
else
|
54
|
+
range_start = offset
|
52
55
|
end
|
53
56
|
|
54
|
-
|
57
|
+
# determine the subset of content that can be displayed
|
58
|
+
range_end = range_start + (available - offset)
|
55
59
|
|
56
60
|
(range_start...range_end)
|
57
61
|
end
|
62
|
+
|
58
63
|
end
|
59
64
|
end
|
data/remedy.gemspec
CHANGED
data/spec/viewport_spec.rb
CHANGED
@@ -1,13 +1,34 @@
|
|
1
|
-
require_relative
|
2
|
-
require
|
1
|
+
require_relative "spec_helper"
|
2
|
+
require "remedy/viewport"
|
3
3
|
|
4
4
|
describe Remedy::Viewport do
|
5
|
+
let(:console){ ::Remedy::Console }
|
6
|
+
let(:size_override){ Size 20, 40 }
|
7
|
+
let(:stringio){ StringIO.new }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
console.input = stringio
|
11
|
+
console.output = stringio
|
12
|
+
console.size_override = size_override
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
console.input = $stdin
|
17
|
+
console.output = $stdout
|
18
|
+
console.size_override = nil
|
19
|
+
end
|
20
|
+
|
5
21
|
it 'should be able to execute the example code from the readme' do
|
22
|
+
expected = "\\e[H\\e[JQ: What's the difference between a duck?\\e[1B\\e[0GA: Purple, because ice cream has no bone\\e[1B\\e[0G"
|
23
|
+
|
6
24
|
joke = ::Remedy::Partial.new
|
7
25
|
joke << "Q: What's the difference between a duck?"
|
8
26
|
joke << "A: Purple, because ice cream has no bones!"
|
9
27
|
|
10
28
|
screen = ::Remedy::Viewport.new
|
11
|
-
screen.draw joke
|
29
|
+
screen.draw joke
|
30
|
+
|
31
|
+
actual = stringio.string.inspect[1..-2]
|
32
|
+
expect(actual).to eq expected
|
12
33
|
end
|
13
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remedy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anthony M. Cook
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: Pure Ruby console interaction library in the vein of Curses with MVC-style
|
28
42
|
seperation of concerns.
|
29
43
|
email:
|
@@ -37,12 +51,13 @@ files:
|
|
37
51
|
- ".gitignore"
|
38
52
|
- ".ruby-gemset"
|
39
53
|
- ".ruby-version"
|
40
|
-
- ".travis.yml"
|
41
54
|
- Gemfile
|
42
55
|
- LICENSE.txt
|
43
56
|
- README.markdown
|
44
57
|
- Rakefile
|
58
|
+
- examples/from_readme/Gemfile
|
45
59
|
- examples/from_readme/readme.rb
|
60
|
+
- examples/menu/Gemfile
|
46
61
|
- examples/menu/menu.rb
|
47
62
|
- lib/remedy.rb
|
48
63
|
- lib/remedy/ansi.rb
|
@@ -75,7 +90,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
90
|
requirements:
|
76
91
|
- - ">="
|
77
92
|
- !ruby/object:Gem::Version
|
78
|
-
version: '
|
93
|
+
version: '2.5'
|
79
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
95
|
requirements:
|
81
96
|
- - ">="
|