vedeu 0.5.13 → 0.6.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/bin/vedeu_drb_server +1 -0
  4. data/config/rubocop_enabled.yml +2 -2
  5. data/docs/events.md +2 -0
  6. data/docs/getting_started.md +1 -1
  7. data/examples/drb_app.rb +1 -0
  8. data/examples/editor_app.rb +76 -0
  9. data/lib/vedeu/all.rb +13 -7
  10. data/lib/vedeu/{bindings.rb → bindings/bindings.rb} +2 -0
  11. data/lib/vedeu/bindings/focus.rb +66 -0
  12. data/lib/vedeu/bindings/refresh.rb +77 -0
  13. data/lib/vedeu/bindings/system.rb +19 -88
  14. data/lib/vedeu/buffers/buffer.rb +8 -8
  15. data/lib/vedeu/configuration/api.rb +32 -11
  16. data/lib/vedeu/configuration/cli.rb +8 -0
  17. data/lib/vedeu/cursor/move.rb +1 -0
  18. data/lib/vedeu/distributed/templates/default_configuration.vedeu +1 -0
  19. data/lib/vedeu/{dsl.rb → dsl/dsl.rb} +0 -0
  20. data/lib/vedeu/exceptions.rb +1 -1
  21. data/lib/vedeu/geometry/position.rb +28 -0
  22. data/lib/vedeu/input/capture.rb +76 -0
  23. data/lib/vedeu/input/editor/all.rb +19 -0
  24. data/lib/vedeu/input/editor/cropper.rb +74 -0
  25. data/lib/vedeu/input/editor/document.rb +254 -0
  26. data/lib/vedeu/input/editor/documents.rb +18 -0
  27. data/lib/vedeu/input/editor/editor.rb +100 -0
  28. data/lib/vedeu/input/editor/line.rb +143 -0
  29. data/lib/vedeu/input/editor/lines.rb +199 -0
  30. data/lib/vedeu/input/editor/virtual_cursor.rb +167 -0
  31. data/lib/vedeu/input/input.rb +9 -93
  32. data/lib/vedeu/input/input_translator.rb +155 -0
  33. data/lib/vedeu/internal_api.rb +9 -0
  34. data/lib/vedeu/log/lockless_log_device.rb +1 -1
  35. data/lib/vedeu/models/escape.rb +7 -8
  36. data/lib/vedeu/output/direct.rb +59 -0
  37. data/lib/vedeu/output/renderers/terminal.rb +8 -0
  38. data/lib/vedeu/output/viewport.rb +2 -3
  39. data/lib/vedeu/{plugins.rb → plugins/plugins.rb} +0 -0
  40. data/lib/vedeu/refresh/refresh_cursor.rb +1 -0
  41. data/lib/vedeu/{repositories.rb → repositories/repositories.rb} +0 -0
  42. data/lib/vedeu/terminal/content.rb +88 -0
  43. data/lib/vedeu/terminal/mode.rb +79 -0
  44. data/lib/vedeu/{terminal.rb → terminal/terminal.rb} +9 -25
  45. data/lib/vedeu/version.rb +1 -1
  46. data/test/lib/vedeu/{bindings_test.rb → bindings/bindings_test.rb} +0 -0
  47. data/test/lib/vedeu/bindings/focus_test.rb +19 -0
  48. data/test/lib/vedeu/bindings/refresh_test.rb +19 -0
  49. data/test/lib/vedeu/bindings/system_test.rb +1 -6
  50. data/test/lib/vedeu/borders/render_border_test.rb +43 -10
  51. data/test/lib/vedeu/buffers/buffer_test.rb +18 -0
  52. data/test/lib/vedeu/buffers/virtual_buffer_test.rb +15 -0
  53. data/test/lib/vedeu/configuration/api_test.rb +18 -2
  54. data/test/lib/vedeu/configuration/cli_test.rb +5 -0
  55. data/test/lib/vedeu/cursor/move_test.rb +1 -1
  56. data/test/lib/vedeu/dsl/dsl_test.rb +8 -0
  57. data/test/lib/vedeu/dsl/shared_test.rb +12 -0
  58. data/test/lib/vedeu/{output → esc}/esc_test.rb +0 -0
  59. data/test/lib/vedeu/geometry/position_test.rb +56 -0
  60. data/test/lib/vedeu/input/capture_test.rb +63 -0
  61. data/test/lib/vedeu/input/editor/cropper_test.rb +82 -0
  62. data/test/lib/vedeu/input/editor/document_test.rb +190 -0
  63. data/test/lib/vedeu/input/editor/documents_test.rb +17 -0
  64. data/test/lib/vedeu/input/editor/editor_test.rb +170 -0
  65. data/test/lib/vedeu/input/editor/line_test.rb +333 -0
  66. data/test/lib/vedeu/input/editor/lines_test.rb +561 -0
  67. data/test/lib/vedeu/input/editor/virtual_cursor_test.rb +184 -0
  68. data/test/lib/vedeu/input/input_test.rb +20 -4
  69. data/test/lib/vedeu/input/input_translator_test.rb +32 -0
  70. data/test/lib/vedeu/internal_api_test.rb +1 -0
  71. data/test/lib/vedeu/models/escape_test.rb +6 -6
  72. data/test/lib/vedeu/models/views/view_test.rb +15 -2
  73. data/test/lib/vedeu/null/null_test.rb +8 -0
  74. data/test/lib/vedeu/output/direct_test.rb +70 -0
  75. data/test/lib/vedeu/{plugins_test.rb → plugins/plugins_test.rb} +0 -0
  76. data/test/lib/vedeu/{repositories_test.rb → repositories/repositories_test.rb} +0 -0
  77. data/test/lib/vedeu/terminal/content_test.rb +100 -0
  78. data/test/lib/vedeu/terminal/mode_test.rb +95 -0
  79. data/test/lib/vedeu/{terminal_test.rb → terminal/terminal_test.rb} +23 -23
  80. data/test/test_helper.rb +1 -0
  81. metadata +67 -20
  82. data/lib/vedeu/terminal_mode.rb +0 -59
  83. data/test/lib/vedeu/terminal_mode_test.rb +0 -72
@@ -78,6 +78,13 @@ module Vedeu
78
78
  true
79
79
  end
80
80
 
81
+ # Clear the buffer.
82
+ #
83
+ # @return [Array<Array<Vedeu::Views::Char>>]
84
+ def clear
85
+ Vedeu::Output.render(Vedeu::Clear::NamedInterface.render(name))
86
+ end
87
+
81
88
  # Return a boolean indicating content presence on the buffer type.
82
89
  #
83
90
  # @return [Boolean] Whether the buffer targetted has content.
@@ -110,7 +117,7 @@ module Vedeu
110
117
  #
111
118
  # @return [Array<Array<Array<Vedeu::Views::Char>>>]
112
119
  def hide
113
- Vedeu::Output.render(clear_buffer)
120
+ Vedeu::Output.render(clear)
114
121
  end
115
122
 
116
123
  # Return the content for this buffer.
@@ -166,13 +173,6 @@ module Vedeu
166
173
  end
167
174
  end
168
175
 
169
- # Clear the buffer.
170
- #
171
- # @return [Array<Array<Vedeu::Views::Char>>]
172
- def clear_buffer
173
- @clear_buffer ||= Vedeu::Clear::NamedInterface.render(name)
174
- end
175
-
176
176
  # Returns the default options/attributes for this class.
177
177
  #
178
178
  # @return [Hash<Symbol => NilClass, String>]
@@ -183,6 +183,20 @@ module Vedeu
183
183
  end
184
184
  alias_method :cooked, :cooked!
185
185
 
186
+ # Sets the terminal mode to `fake`. Default terminal mode is `raw`.
187
+ #
188
+ # @example
189
+ # Vedeu.configure do
190
+ # fake!
191
+ # # ...
192
+ # end
193
+ #
194
+ # @return [Boolean]
195
+ def fake!
196
+ options[:terminal_mode] = :fake
197
+ end
198
+ alias_method :fake, :fake!
199
+
186
200
  # Sets the terminal mode to `raw`. Default terminal mode is `raw`.
187
201
  # Also, see {Vedeu::Config::API#cooked!}
188
202
  #
@@ -390,30 +404,37 @@ module Vedeu
390
404
  end
391
405
  alias_method :compression!, :compression
392
406
 
393
- # Sets the terminal mode. Valid values can be either ':raw' or ':cooked'.
407
+ # Sets the terminal mode. Valid values can be either ':cooked', ':fake' or
408
+ # :raw'.
394
409
  #
395
410
  # Vedeu.configure do
411
+ # terminal_mode :cooked
412
+ #
413
+ # # or...
414
+ #
415
+ # terminal_mode :fake
416
+ #
417
+ # # or...
418
+ #
396
419
  # terminal_mode :raw
397
- # # ...
398
- # end
399
420
  #
400
- # Vedeu.configure do
401
- # terminal_mode :cooked
402
- # # ...
421
+ # # ... some code
403
422
  # end
404
423
  #
405
- # @param mode [Symbol] Either ':raw' or ':cooked'.
406
- # @raise [Vedeu::InvalidSyntax] When the mode is not ':raw' or ':cooked'.
424
+ # @param mode [Symbol] Either ':cooked', ':fake' or ':raw'.
425
+ # @raise [Vedeu::InvalidSyntax] When the mode is not ':cooked', ':fake' or
426
+ # ':raw'.
407
427
  # @return [Symbol]
408
- # @see Vedeu::Config::API#raw!
409
428
  # @see Vedeu::Config::API#cooked!
429
+ # @see Vedeu::Config::API#fake!
430
+ # @see Vedeu::Config::API#raw!
410
431
  def terminal_mode(mode)
411
- if mode == :raw || mode == :cooked
432
+ if [:cooked, :fake, :raw].include?(mode)
412
433
  options[:terminal_mode] = mode
413
434
 
414
435
  else
415
436
  fail Vedeu::InvalidSyntax,
416
- 'Terminal mode can be set to either :raw or :cooked'
437
+ 'Terminal mode can be set to either :cooked, :fake or :raw'
417
438
 
418
439
  end
419
440
  end
@@ -72,6 +72,7 @@ module Vedeu
72
72
  :drb_host,
73
73
  :drb_port,
74
74
  :drb_width,
75
+ :fake,
75
76
  :interactive,
76
77
  :log,
77
78
  :raw,
@@ -194,6 +195,13 @@ module Vedeu
194
195
  #
195
196
  # -i, --interactive
196
197
  #
198
+ # @return [OptionParser]
199
+ def fake
200
+ parser.on('-f', '--fake', 'Run application in fake mode.') do
201
+ options[:terminal_mode] = :fake
202
+ end
203
+ end
204
+
197
205
  # @return [OptionParser]
198
206
  def interactive
199
207
  parser.on('-i', '--interactive',
@@ -182,6 +182,7 @@ module Vedeu
182
182
  @coordinate ||= Vedeu::Coordinate.new(name, oy, ox)
183
183
  end
184
184
 
185
+ # @return [Vedeu::Cursor]
185
186
  # @see Vedeu::Cursors#by_name
186
187
  def cursor
187
188
  @cursor ||= Vedeu.cursors.by_name(name)
@@ -10,6 +10,7 @@ Vedeu.configure do
10
10
 
11
11
  # terminal_mode :raw
12
12
  # cooked!
13
+ # fake!
13
14
  # raw!
14
15
 
15
16
  # run_once!
File without changes
@@ -35,7 +35,7 @@ module Vedeu
35
35
  end # MissingRequired
36
36
 
37
37
  # Raised intentionally when the client application wishes to switch between
38
- # cooked and raw (or vice versa) terminal modes.
38
+ # cooked, fake and raw terminal modes.
39
39
  #
40
40
  # @see Vedeu::Application
41
41
  #
@@ -104,6 +104,34 @@ module Vedeu
104
104
  end
105
105
  alias_method :to_str, :to_s
106
106
 
107
+ # Increase y coordinate; moves down.
108
+ #
109
+ # @return [Vedeu::Position]
110
+ def down
111
+ Vedeu::Position.new(y + 1, x)
112
+ end
113
+
114
+ # Decrease x coordinate; moves left.
115
+ #
116
+ # @return [Vedeu::Position]
117
+ def left
118
+ Vedeu::Position.new(y, x - 1)
119
+ end
120
+
121
+ # Increase x coordinate; moves right.
122
+ #
123
+ # @return [Vedeu::Position]
124
+ def right
125
+ Vedeu::Position.new(y, x + 1)
126
+ end
127
+
128
+ # Decrease y coordinate; moves up.
129
+ #
130
+ # @return [Vedeu::Position]
131
+ def up
132
+ Vedeu::Position.new(y - 1, x)
133
+ end
134
+
107
135
  private
108
136
 
109
137
  # Returns the escape sequence to reposition the cursors at the coordinates
@@ -0,0 +1,76 @@
1
+ module Vedeu
2
+
3
+ module Editor
4
+
5
+ # Capture input from the terminal via 'getch'.
6
+ #
7
+ class Capture
8
+
9
+ ESCAPE_KEY_CODE = 27 # \e
10
+
11
+ # @param console [IO]
12
+ # @return [String|Symbol]
13
+ def self.read(console)
14
+ new(console).read
15
+ end
16
+
17
+ # Returns a new instance of Vedeu::Editor::Capture.
18
+ #
19
+ # @param console [IO]
20
+ # @return [Vedeu::Editor::Capture]
21
+ def initialize(console)
22
+ @console = console
23
+ end
24
+
25
+ # @return [String|Symbol]
26
+ def read
27
+ Vedeu::InputTranslator.translate(keys)
28
+ end
29
+
30
+ private
31
+
32
+ # @return [String]
33
+ def keys
34
+ keys = console.getch
35
+
36
+ if keys.ord == ESCAPE_KEY_CODE
37
+ # Vedeu.log(type: :debug, message: "#keys: Escape detected...")
38
+ @chars = 3
39
+
40
+ begin
41
+ # Vedeu.log(type: :debug,
42
+ # message: "#keys: Attempting read_nonblock(#{@chars})")
43
+ keys << console.read_nonblock(@chars)
44
+
45
+ rescue IO::WaitReadable
46
+ # Vedeu.log(type: :debug,
47
+ # message: "#keys: (#{@chars}) Rescuing IO::WaitReadable")
48
+ IO.select([console])
49
+ @chars -= 1
50
+ retry
51
+
52
+ rescue IO::WaitWritable
53
+ # Vedeu.log(type: :debug,
54
+ # message: "#keys: (#{@chars}) Rescuing IO::WaitWritable")
55
+ IO.select(nil, [console])
56
+ @chars -= 1
57
+ retry
58
+
59
+ end
60
+ end
61
+ # Vedeu.log(type: :debug,
62
+ # message: "#keys: Sending result: #{keys.inspect}")
63
+
64
+ keys
65
+ end
66
+
67
+ # @return [IO]
68
+ def console
69
+ @console || Vedeu::Terminal.console
70
+ end
71
+
72
+ end # Capture
73
+
74
+ end # Editor
75
+
76
+ end # Vedeu
@@ -0,0 +1,19 @@
1
+ module Vedeu
2
+
3
+ # Provide a mechanism to edit individual lines of the view.
4
+ #
5
+ module Editor
6
+
7
+ end # Editor
8
+
9
+ end # Vedeu
10
+
11
+ require 'vedeu/input/capture'
12
+ require 'vedeu/input/editor/editor'
13
+
14
+ require 'vedeu/input/editor/cropper'
15
+ require 'vedeu/input/editor/line'
16
+ require 'vedeu/input/editor/lines'
17
+ require 'vedeu/input/editor/virtual_cursor'
18
+ require 'vedeu/input/editor/document'
19
+ require 'vedeu/input/editor/documents'
@@ -0,0 +1,74 @@
1
+ module Vedeu
2
+
3
+ module Editor
4
+
5
+ # Crop the lines to the visible area of the document, as defined by the
6
+ # geometry provided.
7
+ #
8
+ class Cropper
9
+
10
+ # Returns a new instance of Vedeu::Editor::Cropper.
11
+ #
12
+ # @param lines [Vedeu::Editor::Lines]
13
+ # @param height [Fixnum]
14
+ # @param width [Fixnum]
15
+ # @param ox [Fixnum]
16
+ # @param oy [Fixnum]
17
+ # @return [Vedeu::Editor::Cropper]
18
+ def initialize(lines:, height:, width:, ox:, oy:)
19
+ @lines = lines
20
+ @height = height
21
+ @width = width
22
+ @ox = ox
23
+ @oy = oy
24
+ end
25
+
26
+ # Returns the lines cropped.
27
+ #
28
+ # @note If there are no lines of content, we return an empty array. If
29
+ # there are any empty lines, then they are discarded.
30
+ #
31
+ # @return [Array<void>]
32
+ def cropped
33
+ lines.map { |line| columns(line) }
34
+ end
35
+
36
+ protected
37
+
38
+ # @!attribute [r] height
39
+ # @return [Fixnum]
40
+ attr_reader :height
41
+
42
+ # @!attribute [r] width
43
+ # @return [Fixnum]
44
+ attr_reader :width
45
+
46
+ # @!attribute [r] ox
47
+ # @return [Fixnum]
48
+ attr_reader :ox
49
+
50
+ # @!attribute [r] oy
51
+ # @return [Fixnum]
52
+ attr_reader :oy
53
+
54
+ private
55
+
56
+ # Return a range of visible lines.
57
+ #
58
+ # @return [Vedeu::Editor::Lines]
59
+ def lines
60
+ (@lines[oy...(oy + height)] || [])
61
+ end
62
+
63
+ # Return a range of visible characters from each line.
64
+ #
65
+ # @return [String]
66
+ def columns(line)
67
+ (line[ox...(ox + width)] || '')
68
+ end
69
+
70
+ end # Editor
71
+
72
+ end # Cropper
73
+
74
+ end # Vedeu
@@ -0,0 +1,254 @@
1
+ module Vedeu
2
+
3
+ module Editor
4
+
5
+ # A collection of keypresses ordered by input.
6
+ #
7
+ class Document
8
+
9
+ include Vedeu::Model
10
+ extend Forwardable
11
+
12
+ def_delegators :border,
13
+ :bx,
14
+ :bxn,
15
+ :by,
16
+ :byn,
17
+ :height,
18
+ :width
19
+
20
+ def_delegators :cursor,
21
+ :bol,
22
+ :down,
23
+ :left,
24
+ :ox,
25
+ :oy,
26
+ :right,
27
+ :up,
28
+ :x,
29
+ :y
30
+
31
+ # @!attribute [r] attributes
32
+ # @return [Hash]
33
+ attr_reader :attributes
34
+
35
+ # @!attribute [rw] data
36
+ # @return [String]
37
+ attr_accessor :data
38
+
39
+ # @!attribute [rw] name
40
+ # @return [String]
41
+ attr_accessor :name
42
+
43
+ # Returns a new instance of Vedeu::Editor::Document.
44
+ #
45
+ # @param attributes [Hash]
46
+ # @option attributes data [String]
47
+ # @option attributes name [String]
48
+ # @option attributes repository [Vedeu::Repository]
49
+ # @return [Vedeu::Editor::Document]
50
+ def initialize(attributes = {})
51
+ @attributes = defaults.merge!(attributes)
52
+
53
+ @attributes.each do |key, value|
54
+ instance_variable_set("@#{key}", value || defaults.fetch(key))
55
+ end
56
+ end
57
+
58
+ # Clear the document content in the terminal.
59
+ #
60
+ # @return [void]
61
+ def clear
62
+ Vedeu::Direct.write(value: clear_output, x: bx, y: by)
63
+ end
64
+
65
+ # Deletes the character from the line where the cursor is currently
66
+ # positioned.
67
+ #
68
+ # @return [Vedeu::Editor::Document]
69
+ def delete_character
70
+ @lines = lines.delete_character(y, x - 1)
71
+
72
+ left
73
+
74
+ store
75
+ end
76
+
77
+ # Delete a line.
78
+ #
79
+ # @return [Vedeu::Editor::Document]
80
+ def delete_line
81
+ @lines = lines.delete_line(y)
82
+
83
+ up
84
+
85
+ store
86
+ end
87
+
88
+ # Inserts the given character in to the line where the cursor is currently
89
+ # positioned.
90
+ #
91
+ # @param character [String|Symbol]
92
+ # @return [Vedeu::Editor::Document]
93
+ def insert_character(character)
94
+ return self if character.is_a?(Symbol)
95
+
96
+ @lines = lines.insert_character(character, y, x)
97
+
98
+ right
99
+
100
+ store
101
+ end
102
+
103
+ # Insert an empty line.
104
+ #
105
+ # @return [Vedeu::Editor::Document]
106
+ def insert_line
107
+ down
108
+
109
+ @lines = lines.insert_line(Vedeu::Editor::Line.new, y)
110
+
111
+ bol
112
+
113
+ store
114
+ end
115
+
116
+ # Returns the current line from the collection of lines.
117
+ #
118
+ # @return [Array<String|void>]
119
+ def line
120
+ lines.line(y)
121
+ end
122
+
123
+ # Returns the collection of lines which constitutes the document content.
124
+ #
125
+ # @return [Array<String|void>]
126
+ def lines
127
+ @lines ||= if present?(data)
128
+ Vedeu::Editor::Lines.coerce(data)
129
+
130
+ else
131
+ defaults[:data]
132
+
133
+ end
134
+ end
135
+
136
+ # Render the document content in the terminal.
137
+ #
138
+ # @return [void]
139
+ def render
140
+ clear
141
+
142
+ Vedeu::Direct.write(value: output, x: bx, y: by)
143
+ end
144
+
145
+ # Reset the document to the empty state.
146
+ #
147
+ # @return [Vedeu::Editor::Document]
148
+ def reset!
149
+ @cursor = cursor.reset!
150
+
151
+ @lines = defaults[:data]
152
+
153
+ store
154
+ end
155
+
156
+ # Returns the document as a string with line breaks if there is more than
157
+ # one line.
158
+ #
159
+ # @return [String]
160
+ def retrieve
161
+ lines.map(&:to_s).join("\n")
162
+ end
163
+
164
+ # Store the document in the documents repository and render the view.
165
+ #
166
+ # @return [Vedeu::Editor::Document]
167
+ def store
168
+ super
169
+
170
+ render
171
+
172
+ self
173
+ end
174
+
175
+ private
176
+
177
+ # Retrieve the dimensions of the document from the interface of the same
178
+ # name.
179
+ #
180
+ # @return [Vedeu::Border]
181
+ def border
182
+ @border ||= Vedeu.borders.by_name(name)
183
+ end
184
+
185
+ # Return the data needed to clear the area which the document is using.
186
+ #
187
+ # @return [String]
188
+ def clear_output
189
+ clear_output = ''
190
+
191
+ (by..byn).each do |row|
192
+ clear_output << "\e[#{row};#{bx}H" + (' ' * width)
193
+ end
194
+
195
+ # reset cursor to top left of document
196
+ clear_output << "\e[#{by};#{bx}H"
197
+ end
198
+
199
+ # Returns the default options/attributes for this class.
200
+ #
201
+ # @return [Hash]
202
+ def defaults
203
+ {
204
+ data: Vedeu::Editor::Lines.new([Vedeu::Editor::Line.new]),
205
+ name: nil,
206
+ repository: Vedeu.documents,
207
+ }
208
+ end
209
+
210
+ # Return the data needed to render the document.
211
+ #
212
+ # @return [String]
213
+ def output
214
+ output = ''
215
+
216
+ visible.each_with_index do |line, y_index|
217
+ output << Vedeu::Position.new((by + y_index), bx).to_s + line.to_s
218
+ end
219
+
220
+ output << cursor.to_s
221
+
222
+ output
223
+ end
224
+
225
+ # Return a virtual cursor to track the cursor position within the
226
+ # document.
227
+ #
228
+ # @return [Vedeu::Editor::VirtualCursor]
229
+ def cursor
230
+ @cursor ||= Vedeu::Editor::VirtualCursor.new(y: 0,
231
+ x: 0,
232
+ by: by,
233
+ bx: bx,
234
+ byn: byn,
235
+ bxn: bxn)
236
+ end
237
+
238
+ # Return only the visible lines for the document based on the current
239
+ # virtual cursor position.
240
+ #
241
+ # @return [Vedeu::Editor::Lines]
242
+ def visible
243
+ Vedeu::Editor::Cropper.new(lines: lines,
244
+ height: height,
245
+ width: width,
246
+ ox: ox,
247
+ oy: oy).cropped
248
+ end
249
+
250
+ end # Document
251
+
252
+ end # Editor
253
+
254
+ end # Vedeu