vedeu 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/docs/api.md +2 -0
  3. data/docs/events.md +0 -4
  4. data/examples/cursor_app/cursor_app.rb +56 -44
  5. data/lib/vedeu/api/api.rb +4 -6
  6. data/lib/vedeu/api/composition.rb +3 -7
  7. data/lib/vedeu/api/interface.rb +2 -3
  8. data/lib/vedeu/api/menu.rb +5 -3
  9. data/lib/vedeu/api/stream.rb +34 -0
  10. data/lib/vedeu/application.rb +4 -7
  11. data/lib/vedeu/configuration/api.rb +0 -5
  12. data/lib/vedeu/configuration/cli.rb +0 -1
  13. data/lib/vedeu/configuration/configuration.rb +0 -12
  14. data/lib/vedeu/input/input.rb +0 -3
  15. data/lib/vedeu/launcher.rb +0 -1
  16. data/lib/vedeu/models/{attributes/background.rb → background.rb} +0 -4
  17. data/lib/vedeu/models/char.rb +43 -0
  18. data/lib/vedeu/models/colour.rb +0 -1
  19. data/lib/vedeu/models/composition.rb +4 -3
  20. data/lib/vedeu/models/cursor.rb +70 -146
  21. data/lib/vedeu/models/{attributes/foreground.rb → foreground.rb} +0 -4
  22. data/lib/vedeu/models/geometry.rb +19 -20
  23. data/lib/vedeu/models/interface.rb +36 -5
  24. data/lib/vedeu/models/keymap.rb +7 -4
  25. data/lib/vedeu/models/line.rb +31 -11
  26. data/lib/vedeu/models/offset.rb +84 -0
  27. data/lib/vedeu/models/stream.rb +37 -13
  28. data/lib/vedeu/models/style.rb +0 -1
  29. data/lib/vedeu/output/area.rb +284 -0
  30. data/lib/vedeu/output/clear.rb +2 -4
  31. data/lib/vedeu/output/compositor.rb +0 -4
  32. data/lib/vedeu/output/refresh.rb +1 -2
  33. data/lib/vedeu/output/render.rb +12 -163
  34. data/lib/vedeu/output/view.rb +0 -2
  35. data/lib/vedeu/output/viewport.rb +132 -0
  36. data/lib/vedeu/repositories/buffers.rb +11 -22
  37. data/lib/vedeu/repositories/cursors.rb +20 -47
  38. data/lib/vedeu/repositories/events.rb +2 -1
  39. data/lib/vedeu/repositories/focus.rb +16 -16
  40. data/lib/vedeu/repositories/groups.rb +1 -4
  41. data/lib/vedeu/repositories/interfaces.rb +10 -3
  42. data/lib/vedeu/repositories/keymaps.rb +0 -3
  43. data/lib/vedeu/repositories/menus.rb +0 -2
  44. data/lib/vedeu/repositories/offsets.rb +47 -0
  45. data/lib/vedeu/{models/attributes → support}/coercions.rb +0 -0
  46. data/lib/vedeu/{models/attributes → support}/colour_translator.rb +0 -16
  47. data/lib/vedeu/support/esc.rb +0 -22
  48. data/lib/vedeu/support/event.rb +1 -17
  49. data/lib/vedeu/support/exceptions.rb +0 -3
  50. data/lib/vedeu/support/grid.rb +0 -3
  51. data/lib/vedeu/support/log.rb +13 -14
  52. data/lib/vedeu/support/move.rb +50 -0
  53. data/lib/vedeu/support/position.rb +17 -9
  54. data/lib/vedeu/{models/attributes → support}/presentation.rb +1 -4
  55. data/lib/vedeu/support/registrar.rb +2 -2
  56. data/lib/vedeu/support/repository.rb +23 -2
  57. data/lib/vedeu/support/terminal.rb +0 -2
  58. data/lib/vedeu/support/trace.rb +0 -11
  59. data/lib/vedeu.rb +11 -5
  60. data/test/lib/vedeu/api/api_test.rb +14 -5
  61. data/test/lib/vedeu/api/composition_test.rb +9 -26
  62. data/test/lib/vedeu/api/keymap_test.rb +1 -1
  63. data/test/lib/vedeu/api/menu_test.rb +6 -0
  64. data/test/lib/vedeu/api/stream_test.rb +32 -0
  65. data/test/lib/vedeu/models/{attributes/background_test.rb → background_test.rb} +0 -0
  66. data/test/lib/vedeu/models/char_test.rb +46 -0
  67. data/test/lib/vedeu/models/composition_test.rb +7 -0
  68. data/test/lib/vedeu/models/cursor_test.rb +63 -80
  69. data/test/lib/vedeu/models/{attributes/foreground_test.rb → foreground_test.rb} +0 -0
  70. data/test/lib/vedeu/models/geometry_test.rb +8 -10
  71. data/test/lib/vedeu/models/interface_test.rb +26 -21
  72. data/test/lib/vedeu/models/keymap_test.rb +6 -0
  73. data/test/lib/vedeu/models/line_test.rb +82 -3
  74. data/test/lib/vedeu/models/offset_test.rb +121 -0
  75. data/test/lib/vedeu/models/stream_test.rb +107 -8
  76. data/test/lib/vedeu/output/area_test.rb +242 -0
  77. data/test/lib/vedeu/output/compositor_test.rb +12 -3
  78. data/test/lib/vedeu/output/render_test.rb +34 -39
  79. data/test/lib/vedeu/output/viewport_test.rb +36 -0
  80. data/test/lib/vedeu/repositories/cursors_test.rb +32 -9
  81. data/test/lib/vedeu/repositories/focus_test.rb +8 -0
  82. data/test/lib/vedeu/repositories/offsets_test.rb +32 -0
  83. data/test/lib/vedeu/{models/attributes → support}/coercions_test.rb +0 -0
  84. data/test/lib/vedeu/{models/attributes → support}/colour_translator_test.rb +0 -0
  85. data/test/lib/vedeu/support/move_test.rb +35 -0
  86. data/test/lib/vedeu/{models/attributes → support}/presentation_test.rb +0 -0
  87. data/test/lib/vedeu/support/registrar_test.rb +6 -0
  88. data/test/lib/vedeu_test.rb +5 -0
  89. data/vedeu.gemspec +1 -1
  90. metadata +37 -17
@@ -0,0 +1,84 @@
1
+ module Vedeu
2
+
3
+ # Offset represents the scroll position of the content for an interface. The
4
+ # values herein are relative to the geometry of the interface.
5
+ #
6
+ # @note (to self) An offset is a position. A cursor resides at a position in
7
+ # an interface, ergo we can calculate cursors based from offsets. Also, we
8
+ # could rename Offset to Position, then kill Cursor, Cursors, and the old
9
+ # Position class.
10
+ #
11
+ # @api private
12
+ class Offset
13
+
14
+ attr_reader :name
15
+
16
+ # Returns a new instance of Offset.
17
+ #
18
+ # @param attributes [Hash]
19
+ # @return [Offset]
20
+ def initialize(attributes = {})
21
+ @attributes = defaults.merge!(attributes)
22
+ @name = @attributes[:name]
23
+ @y = @attributes[:y]
24
+ @x = @attributes[:x]
25
+ end
26
+
27
+ # Return a convenient hash of the current values of this instance.
28
+ #
29
+ # @return [Hash]
30
+ def attributes
31
+ {
32
+ name: name,
33
+ y: y,
34
+ x: x,
35
+ }
36
+ end
37
+
38
+ # Adjusts the offset using the relative values provided, and updates the
39
+ # stored attributes. The values passed are -1, 0 or 1.
40
+ #
41
+ # @param relative_y [Fixnum] Move up (-1), or down (1), or no action (0).
42
+ # @param relative_x [Fixnum] Move left (-1), or right (1), or no action (0).
43
+ # @return [Offset]
44
+ def move(relative_y, relative_x)
45
+ @y += relative_y
46
+ @x += relative_x
47
+
48
+ Offsets.update(attributes)
49
+ end
50
+
51
+ # Returns the current x offset, correcting to 0 if less than 0.
52
+ #
53
+ # @return [Fixnum]
54
+ def x
55
+ return @x = 0 if @x <= 0
56
+
57
+ @x
58
+ end
59
+
60
+ # Returns the current y offset, correcting to 0 if less than 0.
61
+ #
62
+ # @return [Fixnum]
63
+ def y
64
+ return @y = 0 if @y <= 0
65
+
66
+ @y
67
+ end
68
+
69
+ private
70
+
71
+ # Return the default values for an instance of Offset.
72
+ #
73
+ # @return [Hash]
74
+ def defaults
75
+ {
76
+ name: '',
77
+ y: 0,
78
+ x: 0,
79
+ }
80
+ end
81
+
82
+ end # Offset
83
+
84
+ end # Vedeu
@@ -40,27 +40,51 @@ module Vedeu
40
40
  end
41
41
  end
42
42
 
43
- # Returns the content of this stream.
43
+ # Returns an array of characters, each element is the escape sequences of
44
+ # colours and styles for this stream, the character itself, and the escape
45
+ # sequences of colours and styles for the parent of the stream
46
+ # ({Vedeu::Line}).
47
+ #
48
+ # @return [Array]
49
+ def chars
50
+ return [] if empty?
51
+
52
+ char_attrs = view_attributes.merge!({ parent: parent })
53
+
54
+ @_chars ||= content.chars.map do |c|
55
+ Char.new(char_attrs.merge!({ value: c })).to_s
56
+ end
57
+ end
58
+
59
+ # Returns the text aligned if a width was set, otherwise just the text. This
60
+ # method also has the alias_method :data, a convenience method to provide
61
+ # Presentation with a consistent interface.
44
62
  #
45
63
  # @return [String]
46
64
  def content
47
- data
65
+ width? ? aligned : text
48
66
  end
67
+ alias_method :data, :content
49
68
 
50
- private
69
+ # Returns a boolean indicating whether the stream has content.
70
+ #
71
+ # @return [Boolean]
72
+ def empty?
73
+ size == 0
74
+ end
51
75
 
52
- # Returns the text aligned if a width was set, otherwise just the text.
76
+ # Returns the size of the content in characters without formatting.
53
77
  #
54
- # @api private
55
- # @return [String]
56
- def data
57
- width? ? aligned : text
78
+ # @return [Fixnum]
79
+ def size
80
+ content.size
58
81
  end
59
82
 
83
+ private
84
+
60
85
  # Returns an aligned string if the string is shorter than the specified
61
86
  # width; the excess area being padded by spaces.
62
87
  #
63
- # @api private
64
88
  # @return [String]
65
89
  def aligned
66
90
  case align
@@ -72,7 +96,6 @@ module Vedeu
72
96
 
73
97
  # Returns a boolean to indicate whether this stream has a width set.
74
98
  #
75
- # @api private
76
99
  # @return [Boolean]
77
100
  def width?
78
101
  !!width
@@ -80,7 +103,6 @@ module Vedeu
80
103
 
81
104
  # The default values for a new instance of Stream.
82
105
  #
83
- # @api private
84
106
  # @return [Hash]
85
107
  def defaults
86
108
  {
@@ -93,12 +115,14 @@ module Vedeu
93
115
  }
94
116
  end
95
117
 
96
- # @api private
118
+ # @param method [Symbol] The name of the method sought.
119
+ # @param args [Array] The arguments which the method was to be invoked with.
120
+ # @param block [Proc] The optional block provided to the method.
97
121
  # @return []
98
122
  def method_missing(method, *args, &block)
99
123
  Vedeu.log("Stream#method_missing '#{method.to_s}' (args: #{args.inspect})")
100
124
 
101
- @self_before_instance_eval.send(method, *args, &block)
125
+ @self_before_instance_eval.send(method, *args, &block) if @self_before_instance_eval
102
126
  end
103
127
 
104
128
  end # Stream
@@ -38,7 +38,6 @@ module Vedeu
38
38
 
39
39
  # Converts the style or styles into terminal escape sequences.
40
40
  #
41
- # @api private
42
41
  # @return [String]
43
42
  def escape_sequences
44
43
  return '' unless defined_value?(values)
@@ -0,0 +1,284 @@
1
+ module Vedeu
2
+
3
+ # Provides a collection of methods useful in calculating geometries for
4
+ # interfaces, cursors and viewports.
5
+ #
6
+ class Area
7
+
8
+ attr_reader :attributes, :height, :x_min, :y_min, :width, :x, :y
9
+
10
+ # Returns an instance of Area.
11
+ #
12
+ # @param interface [Interface]
13
+ # @return [Area]
14
+ def self.from_interface(interface)
15
+ new({
16
+ y_min: interface.top,
17
+ height: interface.height,
18
+ x_min: interface.left,
19
+ width: interface.width
20
+ })
21
+ end
22
+
23
+ # Returns an instance of Area.
24
+ #
25
+ # @param attributes [Hash] The attributes to initialize this class with.
26
+ # @option attributes :y_min [Fixnum] The starting y coordinate for the area,
27
+ # equivalent to +:top+ in {Geometry} parlance.
28
+ # @option attributes :height [Fixnum] The number of rows or lines to use.
29
+ # @option attributes :x_min [Fixnum] The starting x coordinate for the area,
30
+ # equivalent to +:left+ in {Geometry} parlance.
31
+ # @option attributes :width [Fixnum] The number of characters or columns to
32
+ # use.
33
+ # @option attributes :y [Fixnum] A coordinate in the area. This value should
34
+ # be an actual terminal coordinate.
35
+ # @option attributes :x [Fixnum] A coordinate in the area. This value should
36
+ # be an actual terminal coordinate.
37
+ #
38
+ # @return [Area]
39
+ def initialize(attributes = {})
40
+ @attributes = defaults.merge!(attributes)
41
+
42
+ @y_min = @attributes.fetch(:y_min)
43
+ @height = @attributes.fetch(:height)
44
+
45
+ @x_min = @attributes.fetch(:x_min)
46
+ @width = @attributes.fetch(:width)
47
+
48
+ @y = @attributes.fetch(:y)
49
+ @x = @attributes.fetch(:x)
50
+ end
51
+
52
+ # Returns the same as #y_range, except as indices of an array.
53
+ #
54
+ # @example
55
+ # # height = 4
56
+ # y_indices # => [0, 1, 2, 3]
57
+ #
58
+ # @return [Array]
59
+ def y_indices
60
+ (0...height).to_a
61
+ end
62
+
63
+ # Returns the same as #x_range, except as indices of an array.
64
+ #
65
+ # @example
66
+ # # width = 10
67
+ # x_indices # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
68
+ #
69
+ # @return [Array]
70
+ def x_indices
71
+ (0...width).to_a
72
+ end
73
+
74
+ # Returns the maximum y coordinate for an area.
75
+ #
76
+ # @example
77
+ # # y_min = 2
78
+ # # height = 4
79
+ # y_max # => 6
80
+ #
81
+ # @return [Fixnum]
82
+ def y_max
83
+ if height <= 0
84
+ 0
85
+
86
+ else
87
+ y_min + height
88
+
89
+ end
90
+ end
91
+
92
+ # Returns the maximum x coordinate for an area.
93
+ #
94
+ # @example
95
+ # # x_min = 5
96
+ # # width = 20
97
+ # x_max # => 25
98
+ #
99
+ # @return [Fixnum]
100
+ def x_max
101
+ if width <= 0
102
+ 0
103
+
104
+ else
105
+ x_min + width
106
+
107
+ end
108
+ end
109
+
110
+ # Returns the maximum y index for an area.
111
+ #
112
+ # @example
113
+ # # height = 3
114
+ # y_max_index # => 2
115
+ #
116
+ # @return [Fixnum]
117
+ def y_max_index
118
+ return 0 if y_indices.empty?
119
+
120
+ y_indices.last
121
+ end
122
+
123
+ # Returns the maximum x index for an area.
124
+ #
125
+ # @example
126
+ # # width = 6
127
+ # x_max_index # => 5
128
+ #
129
+ # @return [Fixnum]
130
+ def x_max_index
131
+ return 0 if x_indices.empty?
132
+
133
+ x_indices.last
134
+ end
135
+
136
+ # Returns the y coordinate as an offset index in the area's y range. When a
137
+ # value is provided, the y coordinate is overridden. Crudely corrects out of
138
+ # range values.
139
+ #
140
+ # @example
141
+ # # y_range = [7, 8, 9, 10]
142
+ # # y = 8
143
+ # y_index # => 1
144
+ # y_index(10) # => 3
145
+ # y_index(5) # => 0
146
+ # y_index(15) # => 3
147
+ #
148
+ # @param value [Fixnum]
149
+ # @return [Fixnum]
150
+ def y_index(value = y)
151
+ if height <= 0 || value <= y_min
152
+ 0
153
+
154
+ elsif value >= y_max
155
+ y_max_index
156
+
157
+ else
158
+ y_range.index(value)
159
+
160
+ end
161
+ end
162
+
163
+ # Returns the x coordinate as an offset index in the area's x range. When a
164
+ # value is provided, the x coordinate is overridden. Crudely corrects out of
165
+ # range values.
166
+ #
167
+ # @example
168
+ # # x_range = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
169
+ # # x = 8
170
+ # x_index # => 4
171
+ # x_index(11) # => 7
172
+ # x_index(2) # => 0
173
+ # x_index(15) # => 9
174
+ #
175
+ # @param value [Fixnum]
176
+ # @return [Fixnum]
177
+ def x_index(value = x)
178
+ if width <= 0 || value <= x_min
179
+ 0
180
+
181
+ elsif value >= x_max
182
+ x_max_index
183
+
184
+ else
185
+ x_range.index(value)
186
+
187
+ end
188
+ end
189
+
190
+ # Returns the actual position of y for a given index. Crudely corrects out
191
+ # of range values.
192
+ #
193
+ # @example
194
+ # # y_range = [7, 8, 9, 10, 11]
195
+ # y_position # => 7
196
+ # y_position(-2) # => 7
197
+ # y_position(2) # => 9
198
+ # y_position(7) # => 11
199
+ #
200
+ # @param index [Fixnum]
201
+ # @return [Fixnum]
202
+ def y_position(index = 0)
203
+ if index <= 0
204
+ y_min
205
+
206
+ elsif index >= y_max_index
207
+ y_max
208
+
209
+ else
210
+ y_range[index]
211
+
212
+ end
213
+ end
214
+
215
+ # Returns the actual position of x for a given index. Crudely corrects out
216
+ # of range values.
217
+ #
218
+ # @example
219
+ # # x_range = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
220
+ # x_position # => 4
221
+ # x_position(-2) # => 4
222
+ # x_position(2) # => 6
223
+ # x_position(15) # => 13
224
+ #
225
+ # @param index [Fixnum]
226
+ # @return [Fixnum]
227
+ def x_position(index = 0)
228
+ if index <= 0
229
+ x_min
230
+
231
+ elsif index >= x_max_index
232
+ x_max
233
+
234
+ else
235
+ x_range[index]
236
+
237
+ end
238
+ end
239
+
240
+ # Returns an array with all coordinates from x to x_max.
241
+ #
242
+ # @example
243
+ # # width = 10
244
+ # # x_min = 4
245
+ # # x_max = 14
246
+ # x_range # => [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
247
+ #
248
+ # @return [Array]
249
+ def x_range
250
+ (x_min...x_max).to_a
251
+ end
252
+
253
+ # Returns an array with all coordinates from y to y_max.
254
+ #
255
+ # @example
256
+ # # height = 4
257
+ # # y_min = 7
258
+ # # y_max = 11
259
+ # y_range # => [7, 8, 9, 10]
260
+ #
261
+ # @return [Array]
262
+ def y_range
263
+ (y_min...y_max).to_a
264
+ end
265
+
266
+ private
267
+
268
+ # Returns the default attributes for an Area instance.
269
+ #
270
+ # @return [Hash]
271
+ def defaults
272
+ {
273
+ height: 0,
274
+ x_min: 0,
275
+ y_min: 0,
276
+ width: 0,
277
+ x: 0,
278
+ y: 0,
279
+ }
280
+ end
281
+
282
+ end # Area
283
+
284
+ end # Vedeu
@@ -32,7 +32,7 @@ module Vedeu
32
32
  Vedeu.log("Clearing view: '#{interface.name}'")
33
33
 
34
34
  rows.inject([colours]) do |line, index|
35
- line << interface.origin(index) { ' ' * interface.viewport_width }
35
+ line << interface.origin(index) { ' ' * interface.width }
36
36
  end.join
37
37
  end
38
38
 
@@ -40,16 +40,14 @@ module Vedeu
40
40
 
41
41
  attr_reader :interface
42
42
 
43
- # @api private
44
43
  # @return [String]
45
44
  def colours
46
45
  interface.colour.to_s
47
46
  end
48
47
 
49
- # @api private
50
48
  # @return [Enumerator]
51
49
  def rows
52
- interface.viewport_height.times
50
+ interface.height.times
53
51
  end
54
52
 
55
53
  end # Clear
@@ -36,7 +36,6 @@ module Vedeu
36
36
  # Renders the buffer unless empty, otherwise clears the area which the
37
37
  # interface occupies.
38
38
  #
39
- # @api private
40
39
  # @return [String]
41
40
  def view
42
41
  if buffer
@@ -51,7 +50,6 @@ module Vedeu
51
50
  # Combine the buffer attributes with the interface attributes. Buffer
52
51
  # presentation attributes will override interface defaults.
53
52
  #
54
- # @api private
55
53
  # @return [Hash]
56
54
  def new_interface
57
55
  combined = interface
@@ -63,7 +61,6 @@ module Vedeu
63
61
 
64
62
  # Returns the attributes of the named interface (layout).
65
63
  #
66
- # @api private
67
64
  # @return [Hash]
68
65
  def interface
69
66
  @_interface ||= Vedeu::Interfaces.find(name)
@@ -71,7 +68,6 @@ module Vedeu
71
68
 
72
69
  # Returns the attributes of the latest buffer (view).
73
70
  #
74
- # @api private
75
71
  # @return [Hash]
76
72
  def buffer
77
73
  @_buffer ||= Vedeu::Buffers.latest(name)
@@ -37,7 +37,7 @@ module Vedeu
37
37
  # Refresh an interface by name.
38
38
  #
39
39
  # @param name [String] The name of the interface to be refreshed.
40
- # @return [|BufferNotFound]
40
+ # @return [Array|BufferNotFound]
41
41
  def by_name(name)
42
42
  Vedeu::Compositor.render(name)
43
43
  end
@@ -46,7 +46,6 @@ module Vedeu
46
46
  # When the event is called, the interface, or all interfaces belonging to
47
47
  # the group with this name will be refreshed.
48
48
  #
49
- # @api private
50
49
  # @param type [Symbol]
51
50
  # @param name [String]
52
51
  # @param delay [Float]