vedeu 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
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