vedeu 0.5.13 → 0.6.0

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