vedeu 0.2.8 → 0.2.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2156b1bd78d30aece557893b5bf7b96a9253c1b9
4
- data.tar.gz: aac032a4be3cfc9e34dfa6103daafd75502ada05
3
+ metadata.gz: fd5bd7cd569896aed34eadea8a2bb15312c99d4a
4
+ data.tar.gz: ea45bf2468c2ce0d22250da6f2b903ada4ed5028
5
5
  SHA512:
6
- metadata.gz: 84e29f41f956f91c2c48d650a525029e925c22a076490ebf0829c92b42a2935501c8b28e4b8a3d5d6098ff6c2f5126c4d89995d0c11d0b3807e830c1dca1e7c5
7
- data.tar.gz: d30411340d6a5ab8e8fbefb4e612b66bb29a61bc3b5ed74fc220b37ac9ee02accd1caf426df4732982f8657fcee799429bee8032289591565866571e0535e004
6
+ metadata.gz: 796459529347814e7644f0d9c4903c74dd197c93c548f50b06eb2c8fe5fc13c783f93bb8a09e02de6668da7b739310ee0f428521c2a5bf68eb5addc0f3cb32b9
7
+ data.tar.gz: 18c57141d04b4a2f2034ebdbe0384ba05d29a2f6e3ccf64166192c999b55ca6123264da5cfaabd26d3a22d8aee28e5d6f20309caa56131a13270b00bf00639d0
data/lib/vedeu.rb CHANGED
@@ -52,6 +52,7 @@ require 'vedeu/support/position'
52
52
  require 'vedeu/support/esc'
53
53
  require 'vedeu/support/terminal'
54
54
 
55
+ require 'vedeu/models/buffer'
55
56
  require 'vedeu/models/char'
56
57
  require 'vedeu/models/colour'
57
58
  require 'vedeu/models/cursor'
@@ -43,7 +43,7 @@ module Vedeu
43
43
  # - We enter into the main sequence where the application will either run
44
44
  # once or continuous, interactively or standalone.
45
45
  #
46
- # @return []
46
+ # @return [Array] The last output sent to the terminal.
47
47
  def start
48
48
  Terminal.open do
49
49
  Terminal.set_cursor_mode
@@ -0,0 +1,103 @@
1
+ module Vedeu
2
+
3
+ # The Buffer object represents the states of display for an interface. The
4
+ # states are 'front', 'back' and 'previous'.
5
+ #
6
+ # - 'front': The currently displayed buffer; contains the content which was
7
+ # last output.
8
+ # - 'back': The next buffer to be displayed; contains the content which
9
+ # will be shown on next refresh.
10
+ # - 'previous': The previous buffer which was displayed; contains the content
11
+ # that was shown before 'front'.
12
+ #
13
+ class Buffer
14
+
15
+ attr_reader :back, :front, :name, :previous
16
+ alias_method :current, :front
17
+
18
+ # Return a new instance of Buffer.
19
+ #
20
+ # @param attributes [Hash]
21
+ # @return [Buffer]
22
+ def initialize(attributes = {})
23
+ @attributes = defaults.merge(attributes)
24
+
25
+ @name = @attributes[:name]
26
+ @back = @attributes[:back]
27
+ @front = @attributes[:front]
28
+ @previous = @attributes[:previous]
29
+ end
30
+
31
+ # Return a boolean indicating content on the front buffer.
32
+ #
33
+ # @return [Boolean]
34
+ def front?
35
+ front.any? { |k, v| k == :lines && v.any? }
36
+ end
37
+ alias_method :current?, :front?
38
+
39
+ # Return a boolean indicating content on the back buffer.
40
+ #
41
+ # @return [Boolean]
42
+ def back?
43
+ back.any? { |k, v| k == :lines && v.any? }
44
+ end
45
+
46
+ # Return a boolean indicating content on the previous buffer.
47
+ #
48
+ # @return [Boolean]
49
+ def previous?
50
+ previous.any? { |k, v| k == :lines && v.any? }
51
+ end
52
+
53
+ # Add the content to the back buffer, then update the repository. Returns
54
+ # boolean indicating that the repository was updated.
55
+ #
56
+ # @param content [Hash]
57
+ # @return [Boolean]
58
+ def add(content = {})
59
+ self.back = content
60
+
61
+ update!
62
+ end
63
+
64
+ # Return a boolean indicating content was swapped between buffers. It also
65
+ # resets the offsets (i.e. scroll/cursor position).
66
+ #
67
+ # @return [Boolean]
68
+ def swap
69
+ return false unless back?
70
+
71
+ # Offsets.update({ name: name })
72
+
73
+ self.previous = front
74
+ self.front = back
75
+ self.back = {}
76
+
77
+ update!
78
+ end
79
+
80
+ private
81
+
82
+ attr_writer :back, :front, :previous
83
+
84
+ # @see Buffers#update
85
+ def update!
86
+ Buffers.update(self)
87
+ end
88
+
89
+ # Return the default attributes of a Buffer.
90
+ #
91
+ # @return [Hash]
92
+ def defaults
93
+ {
94
+ name: '',
95
+ back: {},
96
+ front: {},
97
+ previous: {},
98
+ }
99
+ end
100
+
101
+ end # Buffer
102
+
103
+ end # Vedeu
@@ -4,31 +4,56 @@ module Vedeu
4
4
  # class is called every time an interface is rendered to prepare the area
5
5
  # for new data.
6
6
  #
7
+ # @note We don't simply clear the entire terminal as this would remove the
8
+ # content of other interfaces which are being displayed.
9
+ #
10
+ # @todo What if an interface 'moves' or changes shape due to the terminal
11
+ # resizing?
12
+ #
7
13
  # @api private
8
14
  class Clear
9
15
 
10
16
  # Blanks the area defined by the interface.
11
17
  #
12
18
  # @param interface [Interface]
19
+ # @param options [Hash]
13
20
  # @return [String]
14
- def self.call(interface)
15
- new(interface).clear
21
+ # @see #initialize
22
+ def self.call(interface, options = {})
23
+ new(interface, options).clear
16
24
  end
17
25
 
18
26
  # Returns a new instance of Clear.
19
27
  #
20
28
  # @param interface [Interface]
29
+ # @param options [Hash]
30
+ # @option options :direct [Boolean] Send escape sequences to clear an area
31
+ # directly to the Terminal.
21
32
  # @return [Clear]
22
- def initialize(interface)
33
+ def initialize(interface, options = {})
23
34
  @interface = interface
35
+ @options = defaults.merge!(options)
24
36
  end
25
37
 
38
+ # Send the cleared area to the terminal.
39
+ #
40
+ # @return [Array]
41
+ def clear
42
+ return Terminal.output(view) if direct?
43
+
44
+ view
45
+ end
46
+
47
+ private
48
+
49
+ attr_reader :interface, :options
50
+
26
51
  # For each visible line of the interface, set the foreground and background
27
52
  # colours to those specified when the interface was defined, then starting
28
53
  # write space characters over the area which the interface occupies.
29
54
  #
30
55
  # @return [String]
31
- def clear
56
+ def view
32
57
  Vedeu.log("Clearing view: '#{interface.name}'")
33
58
 
34
59
  rows.inject([colours]) do |line, index|
@@ -36,10 +61,6 @@ module Vedeu
36
61
  end.join
37
62
  end
38
63
 
39
- private
40
-
41
- attr_reader :interface
42
-
43
64
  # @return [String]
44
65
  def colours
45
66
  interface.colour.to_s
@@ -50,6 +71,18 @@ module Vedeu
50
71
  interface.height.times
51
72
  end
52
73
 
74
+ # @return [Boolean]
75
+ def direct?
76
+ options[:direct]
77
+ end
78
+
79
+ # @return [Hash]
80
+ def defaults
81
+ {
82
+ direct: true
83
+ }
84
+ end
85
+
53
86
  end # Clear
54
87
 
55
88
  end # Vedeu
@@ -38,49 +38,74 @@ module Vedeu
38
38
 
39
39
  # Renders the cursor into the currently focussed interface. May be hidden.
40
40
  #
41
- # @return [String]
41
+ # @return [String] The escape sequence to render the cursor as shown or
42
+ # hidden.
42
43
  def cursor
43
- Interface.new(Vedeu::Interfaces.find(Focus.current)).cursor.to_s
44
+ Interface.new(Interfaces.find(Focus.current)).cursor.to_s
44
45
  end
45
46
 
46
- # Renders the buffer unless empty, otherwise clears the area which the
47
- # interface occupies.
47
+ # Return the content for this buffer.
48
48
  #
49
- # @return [String]
49
+ # - If we have new content (i.e. content on 'back') to be shown, we first
50
+ # clear the area occupied by the previous content, then clear the area for
51
+ # the new content, and then finally render the new content.
52
+ # - If there is no new content (i.e. 'back' is empty), check the 'front'
53
+ # buffer and display that.
54
+ # - If there is no new content, and the front buffer is empty, display the
55
+ # 'previous' buffer.
56
+ # - If the 'previous' buffer is empty, return an empty hash.
57
+ #
58
+ # @return [Hash]
50
59
  def view
51
- if buffer
52
- Render.call(Interface.new(new_interface))
60
+ if buffer.back?
61
+ Clear.call(compose(buffer.previous)) if buffer.previous?
62
+
63
+ buffer.swap
64
+
65
+ Render.call(compose(buffer.front))
66
+
67
+ elsif buffer.front?
68
+ Render.call(compose(buffer.front))
69
+
70
+ elsif buffer.previous?
71
+ Render.call(compose(buffer.previous))
53
72
 
54
73
  else
55
- Clear.call(Interface.new(interface))
74
+ Clear.call(compose({}), { direct: false })
56
75
 
57
76
  end
58
77
  end
59
78
 
60
- # Combine the buffer attributes with the interface attributes. Buffer
61
- # presentation attributes will override interface defaults.
79
+ # Return a new instance of Interface built by combining the buffer content
80
+ # attributes with the stored interface attributes.
62
81
  #
63
- # @return [Hash]
64
- def new_interface
65
- combined = interface
66
- combined[:lines] = buffer[:lines]
67
- combined[:colour] = buffer[:colour] if defined_value?(buffer[:colour])
68
- combined[:style] = buffer[:style] if defined_value?(buffer[:style])
69
- combined
82
+ # @return [Interface]
83
+ def compose(content)
84
+ if defined_value?(content[:geometry])
85
+ content[:geometry].each do |k, v|
86
+ interface[:geometry][k] = v if defined_value?(k)
87
+ end
88
+ end
89
+
90
+ interface[:lines] = content[:lines]
91
+ interface[:colour] = content[:colour] if defined_value?(content[:colour])
92
+ interface[:style] = content[:style] if defined_value?(content[:style])
93
+
94
+ Interface.new(interface)
70
95
  end
71
96
 
72
97
  # Returns the attributes of the named interface (layout).
73
98
  #
74
99
  # @return [Hash]
75
100
  def interface
76
- @_interface ||= Vedeu::Interfaces.find(name)
101
+ @_interface ||= Interfaces.find(name)
77
102
  end
78
103
 
79
- # Returns the attributes of the latest buffer (view).
104
+ # Return the named Buffer (view).
80
105
  #
81
- # @return [Hash|NilClass]
106
+ # @return [Buffer]
82
107
  def buffer
83
- @_buffer ||= Vedeu::Buffers.latest(name)
108
+ @_buffer ||= Buffers.find(name)
84
109
  end
85
110
 
86
111
  end # Compositor
@@ -30,7 +30,7 @@ module Vedeu
30
30
  #
31
31
  # @return [String]
32
32
  def render
33
- out = [clear]
33
+ out = [ Clear.call(interface, { direct: false }) ]
34
34
 
35
35
  Vedeu.log("Rendering view: '#{interface.name}'")
36
36
 
@@ -45,10 +45,6 @@ module Vedeu
45
45
 
46
46
  attr_reader :interface
47
47
 
48
- def clear
49
- Clear.call(interface)
50
- end
51
-
52
48
  end # Render
53
49
 
54
50
  end # Vedeu
@@ -14,107 +14,50 @@ module Vedeu
14
14
  # buffer added to storage.
15
15
  #
16
16
  # @param attributes [Hash]
17
- # @return [String]
17
+ # @return [String] The name of the buffer that has been added.
18
18
  def add(attributes)
19
19
  validate_attributes!(attributes)
20
20
 
21
- if registered?(attributes[:name])
22
- buffer = find(attributes[:name])
21
+ name = attributes[:name]
23
22
 
24
- buffer[:back_buffer] = attributes
23
+ if registered?(name)
24
+ Vedeu.log("Adding new content to existing buffer: '#{name}'")
25
25
 
26
- else
27
- storage.store(attributes[:name], {
28
- back_buffer: attributes,
29
- front_buffer: nil,
30
- })
26
+ find(name).add(attributes)
31
27
 
32
- end
28
+ else
29
+ Vedeu.log("Adding new buffer: '#{name}'")
33
30
 
34
- attributes[:name]
35
- end
31
+ Buffer.new({ name: name }).add(attributes)
36
32
 
37
- # Return the named back buffer.
38
- #
39
- # @param name [String]
40
- # @raise [BufferNotFound] When the named buffer cannot be found.
41
- # @return [Hash|Nil]
42
- def back(name)
43
- find(name)[:back_buffer]
44
- end
33
+ end
45
34
 
46
- # Return the named front buffer.
47
- #
48
- # @param name [String]
49
- # @raise [BufferNotFound] When the named buffer cannot be found.
50
- # @return [Hash|Nil]
51
- def front(name)
52
- find(name)[:front_buffer]
35
+ name
53
36
  end
54
37
 
55
- # Returns the latest content for the named buffer. The latest content always
56
- # goes on to the back buffer. The content which was last output is on the
57
- # front buffer.
58
- #
59
- # When the back buffer has new content, we swap the back onto the front and
60
- # return the front buffer to be rendered.
38
+ # Update the repository with the provided Buffer. Returns a boolean
39
+ # indicating whether this was successful.
61
40
  #
62
- # When the back buffer has no new content, we display that which we
63
- # previously displayed, by returning the front buffer.
64
- #
65
- # If both the back and front buffers have no content, then the view is blank
66
- # and we should return nothing.
67
- #
68
- # @param name [String]
69
- # @return [Hash|NilClass]
70
- def latest(name)
71
- swap_buffers(name) if new_content?(name)
41
+ # @param buffer [Buffer]
42
+ # @return [Boolean]
43
+ def update(buffer)
44
+ storage.store(buffer.name, buffer)
72
45
 
73
- front(name)
46
+ true
74
47
  end
75
48
 
76
49
  private
77
50
 
78
- # Swap the named back buffer into the front buffer of the same name. This is
79
- # called when the back buffer has new content (perhaps as part of a
80
- # refresh). It also resets the offsets (i.e. scroll position)
81
- #
82
- # @param name [String]
83
- # @return [Hash]
84
- def swap_buffers(name)
85
- buffer = find(name)
86
-
87
- Offsets.update({ name: name })
88
-
89
- storage.store(name, {
90
- front_buffer: buffer[:back_buffer],
91
- back_buffer: nil,
92
- })
93
- end
94
-
95
- # Return a boolean indicating whether the named back buffer has new content.
96
- #
97
- # @param name [String]
98
- # @return [Boolean]
99
- def new_content?(name)
100
- defined_value?(back(name))
101
- end
102
-
103
51
  # @return [Hash]
104
52
  def in_memory
105
- Hash.new do |hash, interface_name|
106
- hash[interface_name] = {
107
- front_buffer: nil,
108
- back_buffer: nil,
109
- }
110
- end
53
+ {}
111
54
  end
112
55
 
113
56
  # @param name [String]
114
57
  # @raise [BufferNotFound] When the entity cannot be found with this name.
115
58
  # @return [BufferNotFound]
116
59
  def not_found(name)
117
- fail BufferNotFound, "Cannot find buffer with this name: #{name}."
60
+ fail BufferNotFound, "Cannot find buffer: '#{name}'"
118
61
  end
119
62
 
120
63
  end # Buffers