vedeu 0.1.17 → 0.1.18
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/.yardopts +1 -0
- data/README.md +17 -3
- data/lib/vedeu.rb +12 -7
- data/lib/vedeu/api/api.rb +37 -13
- data/lib/vedeu/api/composition.rb +1 -6
- data/lib/vedeu/api/helpers.rb +2 -0
- data/lib/vedeu/api/interface.rb +47 -55
- data/lib/vedeu/api/line.rb +6 -0
- data/lib/vedeu/api/stream.rb +9 -1
- data/lib/vedeu/application.rb +38 -50
- data/lib/vedeu/configuration.rb +163 -44
- data/lib/vedeu/launcher.rb +3 -6
- data/lib/vedeu/models/attributes/background.rb +9 -1
- data/lib/vedeu/models/attributes/colour_translator.rb +40 -2
- data/lib/vedeu/models/attributes/foreground.rb +9 -1
- data/lib/vedeu/models/colour.rb +6 -0
- data/lib/vedeu/models/composition.rb +8 -1
- data/lib/vedeu/models/geometry.rb +27 -14
- data/lib/vedeu/models/interface.rb +59 -0
- data/lib/vedeu/models/line.rb +4 -0
- data/lib/vedeu/models/stream.rb +10 -0
- data/lib/vedeu/models/style.rb +2 -0
- data/lib/vedeu/support/buffer.rb +12 -1
- data/lib/vedeu/support/buffers.rb +10 -0
- data/lib/vedeu/support/clear.rb +4 -0
- data/lib/vedeu/support/esc.rb +26 -8
- data/lib/vedeu/support/event.rb +28 -0
- data/lib/vedeu/support/events.rb +2 -0
- data/lib/vedeu/support/focus.rb +14 -6
- data/lib/vedeu/support/grid.rb +6 -0
- data/lib/vedeu/support/groups.rb +13 -3
- data/lib/vedeu/support/input.rb +7 -2
- data/lib/vedeu/support/log.rb +7 -1
- data/lib/vedeu/support/position.rb +6 -0
- data/lib/vedeu/support/render.rb +38 -0
- data/lib/vedeu/support/terminal.rb +69 -15
- data/lib/vedeu/support/trace.rb +8 -0
- data/lib/vedeu/support/view.rb +6 -0
- data/test/integration/run_once_test.rb +26 -0
- data/test/lib/vedeu/api/api_test.rb +19 -6
- data/test/lib/vedeu/api/interface_test.rb +67 -1
- data/test/lib/vedeu/api/line_test.rb +10 -0
- data/test/lib/vedeu/api/stream_test.rb +8 -0
- data/test/lib/vedeu/configuration_test.rb +119 -12
- data/test/lib/vedeu/models/attributes/background_test.rb +1 -1
- data/test/lib/vedeu/models/attributes/foreground_test.rb +1 -1
- data/test/lib/vedeu/models/interface_test.rb +22 -0
- data/test/lib/vedeu/support/buffer_test.rb +44 -0
- data/test/lib/vedeu/support/events_test.rb +3 -9
- data/test/lib/vedeu/support/input_test.rb +1 -0
- data/test/lib/vedeu/support/terminal_test.rb +128 -5
- data/test/test_helper.rb +2 -2
- data/vedeu.gemspec +1 -1
- metadata +5 -2
data/lib/vedeu/support/log.rb
CHANGED
@@ -76,7 +76,7 @@ module Vedeu
|
|
76
76
|
|
77
77
|
class Log
|
78
78
|
|
79
|
-
# @return []
|
79
|
+
# @return [TrueClass]
|
80
80
|
def self.logger
|
81
81
|
@logger ||= MonoLogger.new(filename).tap do |log|
|
82
82
|
log.formatter = proc do |_, time, _, message|
|
@@ -87,16 +87,22 @@ module Vedeu
|
|
87
87
|
|
88
88
|
private
|
89
89
|
|
90
|
+
# @api private
|
91
|
+
# @return [String]
|
90
92
|
def self.filename
|
91
93
|
@_filename ||= directory + '/vedeu.log'
|
92
94
|
end
|
93
95
|
|
96
|
+
# @api private
|
97
|
+
# @return [String]
|
94
98
|
def self.directory
|
95
99
|
FileUtils.mkdir_p(path) unless File.directory?(path)
|
96
100
|
|
97
101
|
path
|
98
102
|
end
|
99
103
|
|
104
|
+
# @api private
|
105
|
+
# @return [String]
|
100
106
|
def self.path
|
101
107
|
Dir.home + '/.vedeu'
|
102
108
|
end
|
@@ -22,14 +22,20 @@ module Vedeu
|
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
|
+
# @api private
|
26
|
+
# @return [String]
|
25
27
|
def sequence
|
26
28
|
["\e[", y, ';', x, 'H'].join
|
27
29
|
end
|
28
30
|
|
31
|
+
# @api private
|
32
|
+
# @return [Fixnum]
|
29
33
|
def y
|
30
34
|
(@y == 0 || @y == nil) ? 1 : @y
|
31
35
|
end
|
32
36
|
|
37
|
+
# @api private
|
38
|
+
# @return [Fixnum]
|
33
39
|
def x
|
34
40
|
(@x == 0 || @x == nil) ? 1 : @x
|
35
41
|
end
|
data/lib/vedeu/support/render.rb
CHANGED
@@ -1,18 +1,28 @@
|
|
1
1
|
module Vedeu
|
2
2
|
class Render
|
3
3
|
|
4
|
+
# Attempts to convert the provided interface object with associated lines,
|
5
|
+
# streams, colours, styles, etc, into a single string containing all content
|
6
|
+
# and escape sequences.
|
7
|
+
#
|
8
|
+
# @api private
|
4
9
|
# @param interface [Interface]
|
5
10
|
# @return [String]
|
6
11
|
def self.call(interface)
|
7
12
|
new(interface).render
|
8
13
|
end
|
9
14
|
|
15
|
+
# Initializes a new Render object with the provided interface.
|
16
|
+
#
|
10
17
|
# @param interface [Interface]
|
11
18
|
# @return [Render]
|
12
19
|
def initialize(interface)
|
13
20
|
@interface = interface
|
14
21
|
end
|
15
22
|
|
23
|
+
# Produces a single string which contains all content and escape sequences
|
24
|
+
# required to render this interface to a position in the terminal window.
|
25
|
+
#
|
16
26
|
# @return [String]
|
17
27
|
def render
|
18
28
|
out = [ Clear.call(interface) ]
|
@@ -33,6 +43,9 @@ module Vedeu
|
|
33
43
|
# The client application may have created a line that us too long for the
|
34
44
|
# interface. This code tries to truncate streams whilst preserving styles
|
35
45
|
# and colours.
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @return [Array]
|
36
49
|
def processed_lines
|
37
50
|
return [] unless lines.any? { |line| line.streams.any? }
|
38
51
|
|
@@ -71,22 +84,47 @@ module Vedeu
|
|
71
84
|
end
|
72
85
|
end
|
73
86
|
|
87
|
+
# Converts all streams within a line into a single line of text to then
|
88
|
+
# check that this line (without formatting, as that is not visible) exceeds
|
89
|
+
# the width of the interface.
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
# @param line [Line]
|
93
|
+
# @return [TrueClass|FalseClass]
|
74
94
|
def exceeds_width?(line)
|
75
95
|
line.streams.map(&:text).join.size > width
|
76
96
|
end
|
77
97
|
|
98
|
+
# Truncates the provided text.
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
# @param text [String] The text to be truncated.
|
102
|
+
# @param value [Fixnum] The total length of the text after truncation.
|
103
|
+
# @return [String]
|
78
104
|
def truncate(text, value)
|
79
105
|
text.chomp.slice(0...value)
|
80
106
|
end
|
81
107
|
|
108
|
+
# Provides a collection of lines associated with the interface.
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
# @return [Array]
|
82
112
|
def lines
|
83
113
|
interface.lines
|
84
114
|
end
|
85
115
|
|
116
|
+
# Provides the currently available height of the interface.
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
# @return [Fixnum]
|
86
120
|
def height
|
87
121
|
interface.viewport_height
|
88
122
|
end
|
89
123
|
|
124
|
+
# Provides the currently available width of the interface.
|
125
|
+
#
|
126
|
+
# @api private
|
127
|
+
# @return [Fixnum]
|
90
128
|
def width
|
91
129
|
interface.viewport_width
|
92
130
|
end
|
@@ -1,24 +1,23 @@
|
|
1
1
|
module Vedeu
|
2
2
|
module Terminal
|
3
|
+
|
3
4
|
extend self
|
4
5
|
|
5
|
-
# @param mode [Symbol]
|
6
6
|
# @param block [Proc]
|
7
7
|
# @return []
|
8
|
-
def open(
|
9
|
-
|
8
|
+
def open(&block)
|
9
|
+
fail InvalidSyntax, '`open` requires a block.' unless block_given?
|
10
10
|
|
11
|
-
if
|
12
|
-
|
13
|
-
console.raw { initialize_screen { yield } }
|
11
|
+
if raw_mode?
|
12
|
+
console.raw { initialize_screen { yield } }
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
else
|
15
|
+
console.cooked { initialize_screen { yield } }
|
17
16
|
|
18
|
-
end
|
19
17
|
end
|
20
18
|
ensure
|
21
19
|
restore_screen
|
20
|
+
|
22
21
|
end
|
23
22
|
|
24
23
|
# @return [String]
|
@@ -69,9 +68,35 @@ module Vedeu
|
|
69
68
|
output Esc.string 'show_cursor' unless raw_mode?
|
70
69
|
end
|
71
70
|
|
71
|
+
# @return [Boolean]
|
72
|
+
def cooked_mode?
|
73
|
+
mode == :cooked
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Symbol]
|
77
|
+
def cooked_mode!
|
78
|
+
@_mode = :cooked
|
79
|
+
end
|
80
|
+
|
72
81
|
# @return [Boolean]
|
73
82
|
def raw_mode?
|
74
|
-
|
83
|
+
mode == :raw
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [Symbol]
|
87
|
+
def raw_mode!
|
88
|
+
@_mode = :raw
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [Symbol]
|
92
|
+
def switch_mode!
|
93
|
+
if raw_mode?
|
94
|
+
cooked_mode!
|
95
|
+
|
96
|
+
else
|
97
|
+
raw_mode!
|
98
|
+
|
99
|
+
end
|
75
100
|
end
|
76
101
|
|
77
102
|
# @return [String]
|
@@ -79,26 +104,54 @@ module Vedeu
|
|
79
104
|
Esc.set_position((height - 1), 1) + Esc.string('clear_line')
|
80
105
|
end
|
81
106
|
|
82
|
-
#
|
83
|
-
|
84
|
-
|
107
|
+
# Returns the mode of the terminal, either `:raw` or `:cooked`
|
108
|
+
#
|
109
|
+
# @return [Symbol]
|
110
|
+
def mode
|
111
|
+
@_mode ||= Configuration.terminal_mode
|
85
112
|
end
|
86
113
|
|
114
|
+
# Returns a coordinate tuple of the format [y, x], where `y` is the row/line
|
115
|
+
# and `x` is the column/character.
|
116
|
+
#
|
87
117
|
# @return [Array]
|
88
118
|
def centre
|
89
119
|
[(height / 2), (width / 2)]
|
90
120
|
end
|
91
121
|
|
92
|
-
#
|
122
|
+
# Returns the `y` (row/line) component of the coordinate tuple provided by
|
123
|
+
# {Terminal.centre}
|
124
|
+
#
|
125
|
+
# @return [Fixnum]
|
126
|
+
def centre_y
|
127
|
+
centre.first
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the `x` (column/character) component of the coodinate tuple
|
131
|
+
# provided by {Terminal.centre}
|
132
|
+
#
|
133
|
+
# @return [Fixnum]
|
134
|
+
def centre_x
|
135
|
+
centre.last
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns the total width (number of columns/characters) of the current
|
139
|
+
# terminal.
|
140
|
+
#
|
141
|
+
# @return [Fixnum]
|
93
142
|
def width
|
94
143
|
size.last
|
95
144
|
end
|
96
145
|
|
97
|
-
#
|
146
|
+
# Returns the total height (number of rows/lines) of the current terminal.
|
147
|
+
#
|
148
|
+
# @return [Fixnum]
|
98
149
|
def height
|
99
150
|
size.first
|
100
151
|
end
|
101
152
|
|
153
|
+
# Returns a tuple containing the height and width of the current terminal.
|
154
|
+
#
|
102
155
|
# @return [Array]
|
103
156
|
def size
|
104
157
|
console.winsize
|
@@ -108,5 +161,6 @@ module Vedeu
|
|
108
161
|
def console
|
109
162
|
IO.console
|
110
163
|
end
|
164
|
+
|
111
165
|
end
|
112
166
|
end
|
data/lib/vedeu/support/trace.rb
CHANGED
@@ -28,18 +28,26 @@ module Vedeu
|
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
+
# @api private
|
32
|
+
# @return []
|
31
33
|
def watched
|
32
34
|
options[:event]
|
33
35
|
end
|
34
36
|
|
37
|
+
# @api private
|
38
|
+
# @return []
|
35
39
|
def klass
|
36
40
|
options[:klass]
|
37
41
|
end
|
38
42
|
|
43
|
+
# @api private
|
44
|
+
# @return [Hash]
|
39
45
|
def options
|
40
46
|
defaults.merge!(@options)
|
41
47
|
end
|
42
48
|
|
49
|
+
# @api private
|
50
|
+
# @return [Hash]
|
43
51
|
def defaults
|
44
52
|
{
|
45
53
|
event: 'call',
|
data/lib/vedeu/support/view.rb
CHANGED
@@ -30,14 +30,20 @@ module Vedeu
|
|
30
30
|
|
31
31
|
attr_reader :object
|
32
32
|
|
33
|
+
# @api private
|
34
|
+
# @return [Array]
|
33
35
|
def interfaces
|
34
36
|
composition.interfaces
|
35
37
|
end
|
36
38
|
|
39
|
+
# @api private
|
40
|
+
# @return [Composition]
|
37
41
|
def composition
|
38
42
|
@_composition ||= Composition.new(attributes)
|
39
43
|
end
|
40
44
|
|
45
|
+
# @api private
|
46
|
+
# @return []
|
41
47
|
def attributes
|
42
48
|
render
|
43
49
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MyFirstApplication
|
4
|
+
include Vedeu
|
5
|
+
|
6
|
+
interface 'hydrogen' do
|
7
|
+
x 2
|
8
|
+
y 2
|
9
|
+
width 50
|
10
|
+
height 2
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.start
|
14
|
+
Vedeu::Launcher.new(['--run-once', '--noninteractive']).execute!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'Run the application once, printing a message on the screen and ' \
|
19
|
+
'gracefully terminating.' do
|
20
|
+
it 'writes a message to the screen' do
|
21
|
+
skip
|
22
|
+
stdout, stderr = capture_io { MyFirstApplication.start }
|
23
|
+
stdout.must_equal('Great success! Now, try something a little harder.')
|
24
|
+
stderr.must_equal('')
|
25
|
+
end
|
26
|
+
end
|
@@ -24,10 +24,6 @@ module Vedeu
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe '.events' do
|
27
|
-
it 'should not be visible to the client' do
|
28
|
-
skip
|
29
|
-
end
|
30
|
-
|
31
27
|
it 'returns the Events singleton' do
|
32
28
|
Vedeu.events.must_be_instance_of(Vedeu::Events)
|
33
29
|
end
|
@@ -45,7 +41,7 @@ module Vedeu
|
|
45
41
|
it 'creates and stores a new interface' do
|
46
42
|
Vedeu::Buffers.reset
|
47
43
|
|
48
|
-
Vedeu.interface('Vedeu.interface').
|
44
|
+
Vedeu.interface('Vedeu.interface').must_be_instance_of(API::Interface)
|
49
45
|
end
|
50
46
|
end
|
51
47
|
|
@@ -53,11 +49,24 @@ module Vedeu
|
|
53
49
|
before { event.stubs(:trigger).returns(nil) }
|
54
50
|
|
55
51
|
it 'returns nil' do
|
56
|
-
skip
|
57
52
|
Vedeu.keypress('k').must_equal(nil)
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
56
|
+
describe '.log' do
|
57
|
+
it 'writes the message to the log file when debugging is enabled' do
|
58
|
+
Configuration.stub(:debug?, true) do
|
59
|
+
Vedeu.log('some message...').must_equal(true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns nil when debugging is disabled' do
|
64
|
+
Configuration.stub(:debug?, false) do
|
65
|
+
Vedeu.log('some message...').must_equal(nil)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
61
70
|
describe '.trigger' do
|
62
71
|
it 'triggers the specifed event and returns the collection of events' \
|
63
72
|
' which this trigger triggers' do
|
@@ -128,6 +137,10 @@ module Vedeu
|
|
128
137
|
}
|
129
138
|
)
|
130
139
|
end
|
140
|
+
|
141
|
+
it 'raises an exception if a block was not given' do
|
142
|
+
proc { Vedeu.views }.must_raise(InvalidSyntax)
|
143
|
+
end
|
131
144
|
end
|
132
145
|
|
133
146
|
describe '.width' do
|
@@ -8,7 +8,7 @@ module Vedeu
|
|
8
8
|
interface = Interface.new({ name: 'widget' })
|
9
9
|
|
10
10
|
it 'creates and stores a new interface' do
|
11
|
-
interface.define.
|
11
|
+
interface.define.must_be_instance_of(API::Interface)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'allows the setting of colours' do
|
@@ -834,6 +834,72 @@ module Vedeu
|
|
834
834
|
)
|
835
835
|
end
|
836
836
|
|
837
|
+
it 'allows inline values for line' do
|
838
|
+
Vedeu.interface 'helium' do
|
839
|
+
end
|
840
|
+
attributes = Vedeu.view 'helium' do
|
841
|
+
line 'A headline, if you will.'
|
842
|
+
line # with a spacer line
|
843
|
+
line 'This is a line of text...'
|
844
|
+
line do
|
845
|
+
text '...we can mix and match...'
|
846
|
+
end
|
847
|
+
line '...to our hearts content.'
|
848
|
+
end
|
849
|
+
attributes[:interfaces].first[:lines].size.must_equal(5)
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
describe '#cursor' do
|
854
|
+
it 'raises an exception if the value is invalid' do
|
855
|
+
proc {
|
856
|
+
Vedeu.interface 'beryllium' do
|
857
|
+
cursor :invalid
|
858
|
+
end
|
859
|
+
}.must_raise(InvalidSyntax)
|
860
|
+
end
|
861
|
+
|
862
|
+
it 'sets the cursor to true (visible)' do
|
863
|
+
Vedeu.interface 'beryllium' do
|
864
|
+
cursor true
|
865
|
+
end
|
866
|
+
|
867
|
+
Vedeu.use('beryllium').attributes[:cursor].must_equal(true)
|
868
|
+
end
|
869
|
+
|
870
|
+
it 'sets the cursor to false (hidden)' do
|
871
|
+
Vedeu.interface 'beryllium' do
|
872
|
+
cursor false
|
873
|
+
end
|
874
|
+
|
875
|
+
Vedeu.use('beryllium').attributes[:cursor].must_equal(false)
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
describe '#centred' do
|
880
|
+
it 'raises an exception if the value is invalid' do
|
881
|
+
proc {
|
882
|
+
Vedeu.interface 'boron' do
|
883
|
+
centred :invalid
|
884
|
+
end
|
885
|
+
}.must_raise(InvalidSyntax)
|
886
|
+
end
|
887
|
+
|
888
|
+
it 'sets the centred to true (visible)' do
|
889
|
+
Vedeu.interface 'boron' do
|
890
|
+
centred true
|
891
|
+
end
|
892
|
+
|
893
|
+
Vedeu.use('boron').attributes[:geometry][:centred].must_equal(true)
|
894
|
+
end
|
895
|
+
|
896
|
+
it 'sets the centred to false (hidden)' do
|
897
|
+
Vedeu.interface 'boron' do
|
898
|
+
centred false
|
899
|
+
end
|
900
|
+
|
901
|
+
Vedeu.use('boron').attributes[:geometry][:centred].must_equal(false)
|
902
|
+
end
|
837
903
|
end
|
838
904
|
end
|
839
905
|
end
|