remedy 0.0.5 → 0.3.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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +13 -1
- data/Gemfile +5 -3
- data/README.markdown +31 -13
- data/examples/from_readme/readme.rb +52 -0
- data/examples/menu/menu.rb +74 -0
- data/lib/remedy.rb +1 -2
- data/lib/remedy/ansi.rb +1 -2
- data/lib/remedy/characters.rb +79 -36
- data/lib/remedy/console.rb +17 -13
- data/lib/remedy/console_resize.rb +47 -0
- data/lib/remedy/content.rb +1 -1
- data/lib/remedy/footer.rb +1 -4
- data/lib/remedy/header.rb +1 -4
- data/lib/remedy/interaction.rb +7 -0
- data/lib/remedy/key.rb +10 -2
- data/lib/remedy/partial.rb +3 -2
- data/lib/remedy/size.rb +2 -1
- data/lib/remedy/version.rb +1 -1
- data/lib/remedy/viewport.rb +3 -1
- data/remedy.gemspec +4 -3
- data/spec/key_spec.rb +46 -0
- data/spec/partial_spec.rb +12 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/viewport_spec.rb +13 -0
- metadata +18 -11
- data/lib/remedy/console_resized.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b308f7cf135ba7a8f6ab69ef9c56ff7d640a189c9f44056e14f49b987948ec1f
|
4
|
+
data.tar.gz: 9f1969fea60358a6585974f948f572bdeeeb55afd0f176d6dd220bdd4b29c094
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d664d1b61638b139bd2aef66ed2facd0d25e4dbaa65a39014892bcb3f967895cbf78304a8b4235cce1a5210384e7cadaa6672fa41a2d2e102c22a80c0cd40ef
|
7
|
+
data.tar.gz: ea8a3d1aeaeb8a0e474bf2a69f6837ab300810dfaf3bd014200e284f6e45058875fa5363e73948228806e35e24957ded1d342d07a8622f089726e94da2e93a3b
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.6.3
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
Remedy
|
2
2
|
======
|
3
3
|
|
4
|
-
Remedy is a console interaction framework along the lines of Curses written in pure Ruby
|
4
|
+
Remedy is a console interaction framework along the lines of Curses written in pure Ruby. It is modular, making it easy to use what you need and ignore the rest.
|
5
5
|
|
6
|
-
[](https://rubygems.org/gems/remedy)
|
7
|
+
[](https://rubygems.org/gems/remedy)
|
8
|
+
[](https://travis-ci.org/acook/remedy)
|
9
|
+
[](https://codeclimate.com/github/acook/remedy/maintainability)
|
7
10
|
|
8
|
-
THIS SOFTWARE IS PRE-ALPHA!!
|
9
|
-
----------------------------
|
10
|
-
|
11
|
-
It's under active development and is being used in my own projects. However, expect bugs, missing features, etc.
|
12
11
|
|
13
12
|
If you have any suggestions or find any bugs, drop them in GitHub/issues so I can keep track of them. Thanks!
|
14
13
|
|
@@ -18,13 +17,13 @@ Installation
|
|
18
17
|
Add this line to your application's Gemfile:
|
19
18
|
|
20
19
|
```ruby
|
21
|
-
gem 'remedy'
|
20
|
+
gem 'remedy'
|
22
21
|
```
|
23
22
|
|
24
23
|
If you're only going to use part of Remedy, you can tell Bundler to not automatically require the whole thing:
|
25
24
|
|
26
25
|
```ruby
|
27
|
-
gem 'remedy',
|
26
|
+
gem 'remedy', require: false
|
28
27
|
```
|
29
28
|
|
30
29
|
And then execute:
|
@@ -33,7 +32,7 @@ And then execute:
|
|
33
32
|
|
34
33
|
Or install it yourself as:
|
35
34
|
|
36
|
-
$ gem install remedy
|
35
|
+
$ gem install remedy
|
37
36
|
|
38
37
|
Usage
|
39
38
|
-----
|
@@ -46,6 +45,8 @@ There are objects for input as well as output, including low level console keyst
|
|
46
45
|
|
47
46
|
The `Interaction` object wraps raw keyboard reads and streamlines some aspects of accepting keyboard input.
|
48
47
|
|
48
|
+
For instance to get a keypress from the terminal and display it:
|
49
|
+
|
49
50
|
```ruby
|
50
51
|
include Remedy
|
51
52
|
user_input = Interaction.new
|
@@ -71,7 +72,7 @@ The `Interaction` object wraps raw keyboard reads and streamlines some aspects o
|
|
71
72
|
|
72
73
|
`Remedy::Partial` has the subclasses `Header`, `Footer`, and `Content`.
|
73
74
|
|
74
|
-
You can use the above classes to divide your Views into 3
|
75
|
+
You can use the above classes to divide your Views into 3 separate pieces. Content will be truncated as needed to accommodate the header and footer and the dimensions of the console. You can also specify the cursor/scroll position of the content being drawn, and when specifying headers or footers, you must.
|
75
76
|
|
76
77
|
```ruby
|
77
78
|
include Remedy
|
@@ -99,14 +100,31 @@ The most interesting function in my opinion is the callback that gets triggered
|
|
99
100
|
include Remedy
|
100
101
|
|
101
102
|
screen = Viewport.new
|
102
|
-
notice = Content.new
|
103
|
-
notice << "You just resized your screen!\n\nBrilliant!"
|
104
103
|
|
105
|
-
Console.set_console_resized_hook! do
|
104
|
+
Console.set_console_resized_hook! do |size|
|
105
|
+
notice = Content.new
|
106
|
+
notice << "You just resized your screen!\n\nNew size:"
|
107
|
+
notice << size
|
106
108
|
screen.draw notice
|
107
109
|
end
|
108
110
|
```
|
109
111
|
|
112
|
+
Remedy in the Wild
|
113
|
+
------------------
|
114
|
+
|
115
|
+
Remedy was originally written for my own console-based game which was sort of like Dwarf Fortress. Most of the project files were lost, but since Remedy was extracted from it and open-sourced it has lived on.
|
116
|
+
|
117
|
+
Here are a couple of projects that use many of Remedy's features:
|
118
|
+
- A multiplayer Yahtzee for web and console: [YahtzeeGame](https://github.com/ProgrammingPractice/YahtzeeGame)
|
119
|
+
- Twitter/RSS/Facebook reader: [noizee](https://github.com/acook/noizee)
|
120
|
+
|
121
|
+
Check them out!
|
122
|
+
|
123
|
+
Examples
|
124
|
+
--------
|
125
|
+
|
126
|
+
The `examples` directory has a couple of running implementations to get you started!
|
127
|
+
|
110
128
|
Contributing
|
111
129
|
------------
|
112
130
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require 'remedy'
|
4
|
+
|
5
|
+
include Remedy
|
6
|
+
|
7
|
+
screen = Viewport.new
|
8
|
+
|
9
|
+
Console.set_console_resized_hook! do |size|
|
10
|
+
notice = Content.new
|
11
|
+
notice << "You just resized your screen!\n\nNew size:"
|
12
|
+
notice << size
|
13
|
+
|
14
|
+
screen.draw notice
|
15
|
+
end
|
16
|
+
|
17
|
+
user_input = Interaction.new "press any key to continue"
|
18
|
+
|
19
|
+
joke = Content.new
|
20
|
+
joke << "Q: What's the difference between a duck?"
|
21
|
+
joke << "A: Purple, because ice cream has no bones!"
|
22
|
+
|
23
|
+
screen.draw joke
|
24
|
+
|
25
|
+
user_input.get_key
|
26
|
+
|
27
|
+
title = Header.new
|
28
|
+
title << "Someone Said These Were Good"
|
29
|
+
|
30
|
+
jokes = Content.new
|
31
|
+
jokes << %q{1. A woman gets on a bus with her baby. The bus driver says: 'Ugh, that's the ugliest baby I've ever seen!' The woman walks to the rear of the bus and sits down, fuming. She says to a man next to her: 'The driver just insulted me!' The man says: 'You go up there and tell him off. Go on, I'll hold your monkey for you.'}
|
32
|
+
jokes << %q{2. I went to the zoo the other day, there was only one dog in it, it was a shitzu.}
|
33
|
+
|
34
|
+
disclaimer = Footer.new
|
35
|
+
disclaimer << "According to a survey they were funny. I didn't make them."
|
36
|
+
|
37
|
+
screen.draw jokes, Size.new(0,0), title, disclaimer
|
38
|
+
|
39
|
+
user_input.get_key
|
40
|
+
|
41
|
+
ANSI.cursor.next_line!
|
42
|
+
keys = Content.new
|
43
|
+
loop_demo = Interaction.new "press q to exit, or any other key to display that key's name\n"
|
44
|
+
loop_demo.loop do |key|
|
45
|
+
keys << key
|
46
|
+
|
47
|
+
screen.draw keys
|
48
|
+
break if key == ?q
|
49
|
+
end
|
50
|
+
|
51
|
+
Console.cooked!
|
52
|
+
ANSI.cursor.show!
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
require 'remedy'
|
4
|
+
|
5
|
+
class Menu
|
6
|
+
include Remedy
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@viewport = Viewport.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# will do basic setup and then loop over user input
|
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
|
+
# if the user resizes the screen we redraw it to fit the new dimensions
|
20
|
+
Console.set_console_resized_hook! do |size|
|
21
|
+
draw
|
22
|
+
end
|
23
|
+
|
24
|
+
# create an interaction object to handle user input
|
25
|
+
interaction = Interaction.new
|
26
|
+
|
27
|
+
# call draw here because interaction blocks until it gets input
|
28
|
+
draw
|
29
|
+
|
30
|
+
# loop over user input (individual keypresses)
|
31
|
+
interaction.loop do |key|
|
32
|
+
@last_key = key
|
33
|
+
if key == "q" then
|
34
|
+
interaction.quit!
|
35
|
+
end
|
36
|
+
draw
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# this tells the Viewport to draw to the screen
|
41
|
+
def draw
|
42
|
+
@viewport.draw content, Size([0,0]), header, footer
|
43
|
+
end
|
44
|
+
|
45
|
+
# this is the body of our menu, it will be squished if the terminal is too small
|
46
|
+
def content
|
47
|
+
# this creates a new content every time we draw
|
48
|
+
# you may want to only create a new content/header/footer when they change
|
49
|
+
# or create your own Partial subclass
|
50
|
+
c = Content.new
|
51
|
+
c << <<-CONTENT
|
52
|
+
|
53
|
+
1. Do the thing
|
54
|
+
2. Do other thing
|
55
|
+
3. Do the third thing
|
56
|
+
Q. Quit the thing
|
57
|
+
|
58
|
+
CONTENT
|
59
|
+
c
|
60
|
+
end
|
61
|
+
|
62
|
+
# headers are displayed the top of the viewport
|
63
|
+
def header
|
64
|
+
Header.new << "The time is: #{Time.now}"
|
65
|
+
end
|
66
|
+
|
67
|
+
# footers are displayed the bottom of the viewport
|
68
|
+
def footer
|
69
|
+
Footer.new << "Screen size: #{Console.size} You pressed: #{@last_key}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# display menu and accept user input
|
74
|
+
Menu.new.listen
|
data/lib/remedy.rb
CHANGED
@@ -3,7 +3,7 @@ module Remedy
|
|
3
3
|
|
4
4
|
def libs
|
5
5
|
%w{
|
6
|
-
version ansi characters console
|
6
|
+
version ansi characters console console_resize content header footer
|
7
7
|
interaction key keyboard partial view viewport
|
8
8
|
}
|
9
9
|
end
|
@@ -12,4 +12,3 @@ end
|
|
12
12
|
Remedy.libs.each do |lib|
|
13
13
|
require "remedy/#{lib}"
|
14
14
|
end
|
15
|
-
|
data/lib/remedy/ansi.rb
CHANGED
@@ -117,7 +117,6 @@ module Remedy
|
|
117
117
|
up(lines) + to_column(0)
|
118
118
|
end
|
119
119
|
|
120
|
-
|
121
120
|
def home!
|
122
121
|
pushesc code[:home]
|
123
122
|
end
|
@@ -139,7 +138,7 @@ module Remedy
|
|
139
138
|
end
|
140
139
|
|
141
140
|
def beginning_of_line!
|
142
|
-
to_column
|
141
|
+
to_column 0
|
143
142
|
end
|
144
143
|
|
145
144
|
end
|
data/lib/remedy/characters.rb
CHANGED
@@ -6,6 +6,8 @@ module Remedy
|
|
6
6
|
all[sequence_to_match]
|
7
7
|
end
|
8
8
|
|
9
|
+
# Character Groups
|
10
|
+
|
9
11
|
def all
|
10
12
|
@all ||= printable.merge(nonprintable)
|
11
13
|
end
|
@@ -14,39 +16,46 @@ module Remedy
|
|
14
16
|
@printable ||= whitespace.merge(
|
15
17
|
alphabetical.merge(
|
16
18
|
numeric.merge(
|
17
|
-
punctuation
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
{
|
22
|
-
' ' => :space,
|
23
|
-
"\t" => :tab,
|
24
|
-
"\r" => :carriage_return,
|
25
|
-
"\n" => :line_feed
|
26
|
-
}
|
19
|
+
punctuation
|
20
|
+
)
|
21
|
+
)
|
22
|
+
)
|
27
23
|
end
|
28
24
|
|
29
25
|
def alphabetical
|
30
26
|
@alphabetics ||= get_alphabetics
|
31
27
|
end
|
32
28
|
|
29
|
+
def nonprintable
|
30
|
+
@nonprintable ||= special.merge(directional).merge(escape).merge(control)
|
31
|
+
end
|
32
|
+
|
33
|
+
def whitespace
|
34
|
+
@whitespace ||= {
|
35
|
+
?\s => :space,
|
36
|
+
?\t => :tab,
|
37
|
+
?\r => :carriage_return,
|
38
|
+
?\n => :line_feed
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
33
42
|
def numeric
|
34
|
-
{
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
@numeric ||= {
|
44
|
+
?0 => :zero,
|
45
|
+
?1 => :one,
|
46
|
+
?2 => :two,
|
47
|
+
?3 => :three,
|
48
|
+
?4 => :four,
|
49
|
+
?5 => :five,
|
50
|
+
?6 => :six,
|
51
|
+
?7 => :seven,
|
52
|
+
?8 => :eight,
|
53
|
+
?9 => :nine
|
45
54
|
}
|
46
55
|
end
|
47
56
|
|
48
57
|
def punctuation
|
49
|
-
{
|
58
|
+
@punctuation ||= {
|
50
59
|
'.' => :period,
|
51
60
|
',' => :comma,
|
52
61
|
':' => :colon,
|
@@ -57,7 +66,7 @@ module Remedy
|
|
57
66
|
'`' => :back_quote,
|
58
67
|
|
59
68
|
'[' => :left_bracket,
|
60
|
-
']' => :
|
69
|
+
']' => :right_bracket,
|
61
70
|
'(' => :left_paren,
|
62
71
|
')' => :right_paren,
|
63
72
|
|
@@ -77,18 +86,13 @@ module Remedy
|
|
77
86
|
}
|
78
87
|
end
|
79
88
|
|
80
|
-
def nonprintable
|
81
|
-
@nonprintable ||= special.merge(directional).merge(escape).merge(control)
|
82
|
-
end
|
83
|
-
|
84
89
|
def special
|
85
90
|
{
|
86
|
-
"\177" => :backspace
|
87
91
|
}
|
88
92
|
end
|
89
93
|
|
90
94
|
def directional
|
91
|
-
{
|
95
|
+
@directional ||= {
|
92
96
|
"\e[A" => :up,
|
93
97
|
"\e[B" => :down,
|
94
98
|
"\e[D" => :left,
|
@@ -97,7 +101,7 @@ module Remedy
|
|
97
101
|
end
|
98
102
|
|
99
103
|
def escape
|
100
|
-
{
|
104
|
+
@escape ||= {
|
101
105
|
"\e" => :escape,
|
102
106
|
|
103
107
|
"\e[3~" => :delete
|
@@ -105,13 +109,24 @@ module Remedy
|
|
105
109
|
end
|
106
110
|
|
107
111
|
def control
|
108
|
-
{
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
control_chars = {
|
113
|
+
27.chr => :control_left_square_bracket,
|
114
|
+
28.chr => :control_backslash,
|
115
|
+
29.chr => :control_right_square_bracket,
|
116
|
+
30.chr => :control_caret,
|
117
|
+
31.chr => :control_underscore,
|
118
|
+
127.chr => :delete,
|
119
|
+
177.chr => :backspace
|
112
120
|
}
|
121
|
+
(?a..?z).each.with_index do |letter, index|
|
122
|
+
control_chars.merge!({(index + 1).chr => "control_#{letter}".to_sym})
|
123
|
+
end
|
124
|
+
|
125
|
+
control_chars
|
113
126
|
end
|
114
127
|
|
128
|
+
# Glyphs and Alternate Names
|
129
|
+
|
115
130
|
def gremlins
|
116
131
|
{
|
117
132
|
space: "\u2420",
|
@@ -137,10 +152,38 @@ module Remedy
|
|
137
152
|
|
138
153
|
def alternate_names
|
139
154
|
{
|
155
|
+
control_a: :start_of_heading,
|
156
|
+
control_b: :start_of_text,
|
140
157
|
control_c: :end_of_transmission,
|
141
158
|
control_d: :end_of_text,
|
142
|
-
|
143
|
-
|
159
|
+
control_e: :enquiry,
|
160
|
+
control_f: :acknowledge,
|
161
|
+
control_g: :bel,
|
162
|
+
control_h: :backspace,
|
163
|
+
control_i: :horizontal_tabulation,
|
164
|
+
control_j: :line_feed,
|
165
|
+
control_k: :vertical_tabulation,
|
166
|
+
control_l: :form_feed,
|
167
|
+
control_m: :carriage_return,
|
168
|
+
control_n: :shift_out,
|
169
|
+
control_o: :shift_in,
|
170
|
+
control_p: :data_link_escape,
|
171
|
+
control_q: :device_control_one,
|
172
|
+
control_r: :device_control_two,
|
173
|
+
control_s: :device_control_three,
|
174
|
+
control_t: :device_control_four,
|
175
|
+
control_u: :negative_acknowledge,
|
176
|
+
control_v: :sychnronous_idle,
|
177
|
+
control_w: :end_of_transmission_block,
|
178
|
+
control_x: :cancel,
|
179
|
+
control_y: :end_of_medium,
|
180
|
+
control_z: :substitute,
|
181
|
+
|
182
|
+
control_left_square_bracket: :escape,
|
183
|
+
control_backslash: :file_separator,
|
184
|
+
control_right_square_bracket: :group_separator,
|
185
|
+
control_caret: :record_separator,
|
186
|
+
control_underscore: :unit_separator
|
144
187
|
}
|
145
188
|
end
|
146
189
|
|
data/lib/remedy/console.rb
CHANGED
@@ -1,19 +1,26 @@
|
|
1
|
-
require 'remedy/
|
1
|
+
require 'remedy/console_resize'
|
2
2
|
|
3
3
|
module Remedy
|
4
4
|
module Console
|
5
5
|
require 'io/console'
|
6
6
|
|
7
|
-
TIOCGWINSZ =
|
7
|
+
TIOCGWINSZ = case RbConfig::CONFIG['host_os']
|
8
|
+
when /darwin|mac os/
|
9
|
+
0x40087468
|
10
|
+
when /linux/
|
11
|
+
0x5413
|
12
|
+
else
|
13
|
+
0x00
|
14
|
+
end
|
8
15
|
|
9
16
|
module_function
|
10
17
|
|
11
18
|
def input
|
12
|
-
|
19
|
+
@input ||= $stdin
|
13
20
|
end
|
14
21
|
|
15
22
|
def output
|
16
|
-
|
23
|
+
@output ||= $stdout
|
17
24
|
end
|
18
25
|
|
19
26
|
def raw
|
@@ -21,7 +28,6 @@ module Remedy
|
|
21
28
|
result = yield
|
22
29
|
ensure
|
23
30
|
cooked!
|
24
|
-
|
25
31
|
return result
|
26
32
|
end
|
27
33
|
|
@@ -33,24 +39,22 @@ module Remedy
|
|
33
39
|
def cooked!
|
34
40
|
input.echo = true
|
35
41
|
input.cooked!
|
36
|
-
rescue NoMethodError
|
37
|
-
%x{stty -raw echo 2> /dev/null}
|
38
42
|
end
|
39
43
|
|
40
44
|
def columns
|
41
|
-
size.
|
45
|
+
size.cols
|
42
46
|
end
|
43
47
|
alias_method :width, :columns
|
44
|
-
|
48
|
+
|
45
49
|
def rows
|
46
|
-
size.
|
50
|
+
size.rows
|
47
51
|
end
|
48
52
|
alias_method :height, :rows
|
49
53
|
|
50
54
|
def size
|
51
55
|
str = [0, 0, 0, 0].pack('SSSS')
|
52
56
|
if input.ioctl(TIOCGWINSZ, str) >= 0 then
|
53
|
-
str.unpack('SSSS').first 2
|
57
|
+
Size.new str.unpack('SSSS').first 2
|
54
58
|
else
|
55
59
|
raise UnknownConsoleSize, "Unable to get console size"
|
56
60
|
end
|
@@ -61,8 +65,8 @@ module Remedy
|
|
61
65
|
end
|
62
66
|
|
63
67
|
def set_console_resized_hook!
|
64
|
-
|
65
|
-
yield
|
68
|
+
Console::Resize.set_console_resized_hook! do |*args|
|
69
|
+
yield *args
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Remedy; module Console; module Resize
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def resizing?
|
5
|
+
@resize_count > 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def resizing!
|
9
|
+
@resize_count = @resize_count < 1 ? 1 : @resize_count + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def resized?
|
13
|
+
@resize_count <= 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def resized!
|
17
|
+
@resize_count = @resize_count < 0 ? 0 : @resize_count - 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def resizer?
|
21
|
+
@resize_count == 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_console_resized_hook!
|
25
|
+
@resize_count = 0
|
26
|
+
|
27
|
+
Signal.trap 'SIGWINCH' do
|
28
|
+
resizing!
|
29
|
+
|
30
|
+
if resized? then
|
31
|
+
begin
|
32
|
+
yield Console.size
|
33
|
+
rescue Exception => ex
|
34
|
+
# Ruby will eat *any* errors inside a trap,
|
35
|
+
# so we need to expose them for debuggability
|
36
|
+
p ex
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
resized!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_console_resized_hook!
|
45
|
+
Signal.trap 'SIGWINCH', 'DEFAULT'
|
46
|
+
end
|
47
|
+
end; end; end
|
data/lib/remedy/content.rb
CHANGED
data/lib/remedy/footer.rb
CHANGED
data/lib/remedy/header.rb
CHANGED
data/lib/remedy/interaction.rb
CHANGED
data/lib/remedy/key.rb
CHANGED
@@ -15,6 +15,10 @@ module Remedy
|
|
15
15
|
seq
|
16
16
|
end
|
17
17
|
|
18
|
+
def enc
|
19
|
+
seq.dump[1..-2]
|
20
|
+
end
|
21
|
+
|
18
22
|
def name
|
19
23
|
@name ||= Characters[seq] || :unknown
|
20
24
|
end
|
@@ -51,16 +55,20 @@ module Remedy
|
|
51
55
|
@recognized ||= name != :unknown
|
52
56
|
end
|
53
57
|
|
58
|
+
def known?
|
59
|
+
!!Characters[seq]
|
60
|
+
end
|
61
|
+
|
54
62
|
def single?
|
55
63
|
@single ||= raw.length == 1
|
56
64
|
end
|
57
65
|
|
58
66
|
def sequence?
|
59
|
-
@sequence ||= raw.
|
67
|
+
@sequence ||= raw.length > 1
|
60
68
|
end
|
61
69
|
|
62
70
|
def to_s
|
63
|
-
@to_s ||= name.to_s
|
71
|
+
@to_s ||= known? ? name.to_s : enc
|
64
72
|
end
|
65
73
|
|
66
74
|
def value
|
data/lib/remedy/partial.rb
CHANGED
@@ -14,6 +14,7 @@ module Remedy
|
|
14
14
|
|
15
15
|
def << line
|
16
16
|
reset_width!
|
17
|
+
line = "#{line}" # opportunistically convert any object into a string
|
17
18
|
@lines += clean line unless line.nil? || line.empty?
|
18
19
|
end
|
19
20
|
|
@@ -30,7 +31,7 @@ module Remedy
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def width
|
33
|
-
@width ||= lines.max{|line| line.length }
|
34
|
+
@width ||= lines.max{|line| line.length }.length
|
34
35
|
end
|
35
36
|
|
36
37
|
def size
|
@@ -64,7 +65,7 @@ module Remedy
|
|
64
65
|
end
|
65
66
|
|
66
67
|
def split line
|
67
|
-
line.split
|
68
|
+
line.split(/\r\n|\n\r|\n|\r/)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
end
|
data/lib/remedy/size.rb
CHANGED
data/lib/remedy/version.rb
CHANGED
data/lib/remedy/viewport.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'remedy/view'
|
2
2
|
require 'remedy/size'
|
3
3
|
require 'remedy/content'
|
4
|
+
require 'remedy/console'
|
5
|
+
require 'remedy/ansi'
|
4
6
|
|
5
7
|
module Remedy
|
6
8
|
class Viewport
|
@@ -23,7 +25,7 @@ module Remedy
|
|
23
25
|
row_size, col_size = heightwidth
|
24
26
|
row_limit, col_limit = partial.size
|
25
27
|
|
26
|
-
center_row, center_col = center
|
28
|
+
center_row, center_col = center
|
27
29
|
|
28
30
|
row_range = center_range center_row, row_size, row_limit
|
29
31
|
col_range = center_range center_col, col_size, col_limit
|
data/remedy.gemspec
CHANGED
@@ -7,9 +7,10 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.name = "remedy"
|
8
8
|
gem.version = Remedy::VERSION
|
9
9
|
gem.authors = ["Anthony M. Cook"]
|
10
|
-
gem.email = ["
|
11
|
-
gem.description = %q{Pure Ruby console interaction library in the vein of Curses with
|
12
|
-
gem.summary = %q{
|
10
|
+
gem.email = ["github@anthonymcook.com"]
|
11
|
+
gem.description = %q{Pure Ruby console interaction library in the vein of Curses with MVC-style seperation of concerns.}
|
12
|
+
gem.summary = %q{Pure Ruby Console Interaction Library}
|
13
|
+
gem.licenses = ['MIT']
|
13
14
|
gem.homepage = "http://github.com/acook/remedy"
|
14
15
|
|
15
16
|
gem.files = `git ls-files`.split($/)
|
data/spec/key_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'remedy/key'
|
3
|
+
|
4
|
+
describe Remedy::Key do
|
5
|
+
subject(:key){ described_class.new keypress }
|
6
|
+
|
7
|
+
let(:keypress){ "\e[A" }
|
8
|
+
|
9
|
+
describe '#raw' do
|
10
|
+
it 'gives the same sequence it was initialized with' do
|
11
|
+
expect(key.raw).to equal(keypress)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#name' do
|
16
|
+
it 'gives the name of the key' do
|
17
|
+
expect(key.name).to equal(:up)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#glyph' do
|
22
|
+
it 'gives the individual character respresentation of the key' do
|
23
|
+
expect(key.glyph).to eq("\u2191")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#nonprintable?' do
|
28
|
+
it 'indicates that a keypress is a nonprintable character or sequence' do
|
29
|
+
expect(key.nonprintable?).to be(true)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#sequence?' do
|
34
|
+
it 'determines if a keypress is an escape sequence' do
|
35
|
+
expect(key.sequence?).to be(true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'control characters' do
|
40
|
+
let(:keypress){ 3.chr }
|
41
|
+
|
42
|
+
it 'recognizes control c' do
|
43
|
+
expect(key.control_c?).to be(true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'remedy/partial'
|
3
|
+
|
4
|
+
describe Remedy::Partial do
|
5
|
+
subject { described_class.new.tap{|p| p << "foo"; p << "bar"; p << "remedy" } }
|
6
|
+
|
7
|
+
describe '#width' do
|
8
|
+
it 'gives length of longest line' do
|
9
|
+
expect(subject.width).to eq 6
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'remedy/viewport'
|
3
|
+
|
4
|
+
describe Remedy::Viewport do
|
5
|
+
it 'should be able to execute the example code from the readme' do
|
6
|
+
joke = ::Remedy::Content.new
|
7
|
+
joke << "Q: What's the difference between a duck?"
|
8
|
+
joke << "A: Purple, because ice cream has no bones!"
|
9
|
+
|
10
|
+
screen = ::Remedy::Viewport.new
|
11
|
+
screen.draw joke unless ENV['CI']
|
12
|
+
end
|
13
|
+
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.0
|
4
|
+
version: 0.3.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: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
description: Pure Ruby console interaction library in the vein of Curses with
|
28
|
-
|
27
|
+
description: Pure Ruby console interaction library in the vein of Curses with MVC-style
|
28
|
+
seperation of concerns.
|
29
29
|
email:
|
30
|
-
-
|
30
|
+
- github@anthonymcook.com
|
31
31
|
executables: []
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files: []
|
@@ -40,11 +40,13 @@ files:
|
|
40
40
|
- LICENSE.txt
|
41
41
|
- README.markdown
|
42
42
|
- Rakefile
|
43
|
+
- examples/from_readme/readme.rb
|
44
|
+
- examples/menu/menu.rb
|
43
45
|
- lib/remedy.rb
|
44
46
|
- lib/remedy/ansi.rb
|
45
47
|
- lib/remedy/characters.rb
|
46
48
|
- lib/remedy/console.rb
|
47
|
-
- lib/remedy/
|
49
|
+
- lib/remedy/console_resize.rb
|
48
50
|
- lib/remedy/content.rb
|
49
51
|
- lib/remedy/footer.rb
|
50
52
|
- lib/remedy/header.rb
|
@@ -57,10 +59,14 @@ files:
|
|
57
59
|
- lib/remedy/view.rb
|
58
60
|
- lib/remedy/viewport.rb
|
59
61
|
- remedy.gemspec
|
62
|
+
- spec/key_spec.rb
|
63
|
+
- spec/partial_spec.rb
|
60
64
|
- spec/remedy_spec.rb
|
61
65
|
- spec/spec_helper.rb
|
66
|
+
- spec/viewport_spec.rb
|
62
67
|
homepage: http://github.com/acook/remedy
|
63
|
-
licenses:
|
68
|
+
licenses:
|
69
|
+
- MIT
|
64
70
|
metadata: {}
|
65
71
|
post_install_message:
|
66
72
|
rdoc_options: []
|
@@ -77,12 +83,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
83
|
- !ruby/object:Gem::Version
|
78
84
|
version: '0'
|
79
85
|
requirements: []
|
80
|
-
|
81
|
-
rubygems_version: 2.6.4
|
86
|
+
rubygems_version: 3.1.2
|
82
87
|
signing_key:
|
83
88
|
specification_version: 4
|
84
|
-
summary:
|
89
|
+
summary: Pure Ruby Console Interaction Library
|
85
90
|
test_files:
|
91
|
+
- spec/key_spec.rb
|
92
|
+
- spec/partial_spec.rb
|
86
93
|
- spec/remedy_spec.rb
|
87
94
|
- spec/spec_helper.rb
|
88
|
-
|
95
|
+
- spec/viewport_spec.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Remedy
|
2
|
-
module ConsoleResized
|
3
|
-
module_function
|
4
|
-
|
5
|
-
def resizing?
|
6
|
-
@resize_count > 0
|
7
|
-
end
|
8
|
-
|
9
|
-
def resizing!
|
10
|
-
@resize_count = @resize_count < 1 ? 1 : @resize_count + 1
|
11
|
-
end
|
12
|
-
|
13
|
-
def resized?
|
14
|
-
@resize_count <= 1
|
15
|
-
end
|
16
|
-
|
17
|
-
def resized!
|
18
|
-
@resize_count = @resize_count < 0 ? 0 : @resize_count - 1
|
19
|
-
end
|
20
|
-
|
21
|
-
def resizer?
|
22
|
-
@resize_count == 1
|
23
|
-
end
|
24
|
-
|
25
|
-
def set_console_resized_hook!
|
26
|
-
@resize_count = 0
|
27
|
-
|
28
|
-
command = lambda { |x|
|
29
|
-
resizing!
|
30
|
-
sleep 0.25
|
31
|
-
|
32
|
-
if resized? then
|
33
|
-
yield
|
34
|
-
end
|
35
|
-
|
36
|
-
resized!
|
37
|
-
}
|
38
|
-
|
39
|
-
Signal.trap 'SIGWINCH', command
|
40
|
-
end
|
41
|
-
|
42
|
-
def default_console_resized_hook!
|
43
|
-
Signal.trap 'SIGWINCH', 'DEFAULT'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|