rtext 0.4.0 → 0.5.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 (48) hide show
  1. data/CHANGELOG +20 -0
  2. data/{README → README.rdoc} +5 -1
  3. data/RText_Protocol +444 -0
  4. data/Rakefile +10 -10
  5. data/lib/rtext/completer.rb +32 -26
  6. data/lib/rtext/context_builder.rb +113 -59
  7. data/lib/rtext/default_loader.rb +73 -8
  8. data/lib/rtext/default_service_provider.rb +30 -14
  9. data/lib/rtext/frontend/config.rb +58 -0
  10. data/lib/rtext/frontend/connector.rb +233 -0
  11. data/lib/rtext/frontend/connector_manager.rb +81 -0
  12. data/lib/rtext/frontend/context.rb +56 -0
  13. data/lib/rtext/generic.rb +13 -0
  14. data/lib/rtext/instantiator.rb +30 -7
  15. data/lib/rtext/language.rb +54 -27
  16. data/lib/rtext/link_detector.rb +57 -0
  17. data/lib/rtext/message_helper.rb +77 -0
  18. data/lib/rtext/parser.rb +19 -68
  19. data/lib/rtext/serializer.rb +18 -3
  20. data/lib/rtext/service.rb +182 -118
  21. data/lib/rtext/tokenizer.rb +102 -0
  22. data/test/completer_test.rb +327 -70
  23. data/test/context_builder_test.rb +671 -91
  24. data/test/instantiator_test.rb +153 -0
  25. data/test/integration/backend.out +10 -0
  26. data/test/integration/crash_on_request_editor.rb +12 -0
  27. data/test/integration/ecore_editor.rb +50 -0
  28. data/test/integration/frontend.log +25138 -0
  29. data/test/integration/model/invalid_encoding.invenc +2 -0
  30. data/test/integration/model/test.crash_on_request +18 -0
  31. data/test/integration/model/test.crashing_backend +18 -0
  32. data/test/integration/model/test.dont_open_socket +0 -0
  33. data/test/integration/model/test.invalid_cmd_line +0 -0
  34. data/test/integration/model/test.not_in_rtext +0 -0
  35. data/test/integration/model/test_large_with_errors.ect3 +43523 -0
  36. data/test/integration/model/test_metamodel.ect +18 -0
  37. data/test/integration/model/test_metamodel2.ect +5 -0
  38. data/test/integration/model/test_metamodel_error.ect2 +3 -0
  39. data/test/integration/model/test_metamodel_ok.ect2 +18 -0
  40. data/test/integration/test.rb +684 -0
  41. data/test/link_detector_test.rb +276 -0
  42. data/test/message_helper_test.rb +118 -0
  43. data/test/rtext_test.rb +4 -1
  44. data/test/serializer_test.rb +96 -1
  45. data/test/tokenizer_test.rb +125 -0
  46. metadata +36 -10
  47. data/RText_Plugin_Implementation_Guide +0 -268
  48. data/lib/rtext_plugin/connection_manager.rb +0 -59
data/CHANGELOG CHANGED
@@ -23,3 +23,23 @@
23
23
  * Fixed used port detection in service
24
24
  * Fixed completion option order to match order defined in lanugage
25
25
 
26
+ =0.5.0
27
+
28
+ * Added annotations
29
+ * Added generic value support
30
+ * Added RText frontend support (for Ruby based RText plugins and testing)
31
+ * Changed frontend/backend protocol to JSON over TCP
32
+ * Generally improved completer and context builder, fixed bugs, added tests
33
+ * Added automated frontend/backend tests
34
+ * Added example language (ECore editor)
35
+ * Added configurable backward reference attribute
36
+ * Fixed backward reference resolution in case line ends with name attribute
37
+ * Added more information to unlabled value completion options
38
+ * Added backend service support for lanugage exchange at runtime
39
+ * Extended support for relative reference calculation and resolution
40
+ * Added on_progress hook to default_loader
41
+ * Added explicit handling of encoding
42
+ * Improved backend service progress reporting
43
+ * Fixed backward reference list to not include opposites of forward references
44
+ * Fixed problem with backend service socket connection on some machines
45
+
@@ -17,6 +17,10 @@ RText features include:
17
17
 
18
18
  > gem install rtext
19
19
 
20
+ The RText service protocol requires the JSON gem:
21
+
22
+ > gem install json
23
+
20
24
 
21
25
  = Documentation
22
26
 
@@ -26,4 +30,4 @@ RText features include:
26
30
 
27
31
  = License
28
32
 
29
- RGen is released under the MIT license.
33
+ RText is released under the MIT license.
@@ -0,0 +1,444 @@
1
+ = RText Protocol
2
+
3
+ RText frontend and backend pass messages containing JSON objects.
4
+ Normally the frontend invokes a backend command by means of a request message and the
5
+ backend will eventually reply with a response message.
6
+
7
+
8
+ == Encoding
9
+
10
+ As the RText protocol uses JSON, the encoding of messages is UTF-8 by definition.
11
+ However, the protocol further restricts UTF-8 to only 7-BIT-ASCII characters, which
12
+ effectively makes the protocol encoding 7-BIT-ASCII (or US-ASCII), which is valid UTF-8.
13
+
14
+ Frontends and backends should not apply any transcoding to the data found in RText files.
15
+ The reason is, that most often information about an input file's encoding is not reliable.
16
+ If the source encoding is wrong, transcoding just makes things worse: either data is
17
+ misinterpreted or information is lost due to character replacement.
18
+
19
+ Instead, data should be passed as is, or in other words: it should be interpreted as
20
+ "binary" data. Since the RText protocol is restricted to 7-BIT-ASCII, all non 7-BIT-ASCII
21
+ characters are escaped using the following pattern: Each byte with a value of 0x80 or higher
22
+ results in three 7-BIT-ASCII characters: a leading "%" and two hexadecimal figures in lower case.
23
+ In addition, the character "%" is escaped in the same way, i.e. "%" will always be escaped as
24
+ "%25" ("%" has byte value 0x25 in 7-BIT-ASCII).
25
+
26
+ Example:
27
+
28
+ The word "�bung" (german: exercise), encoded in ISO-8859-1 would result in the string:
29
+ "%dcbung" (the "�" Umlaut has a byte value of 0xdc is ISO-8859-1).
30
+
31
+
32
+ == Request Messages
33
+
34
+ Each request message contains a field ``command`` and a field ``invocation_id``.
35
+ The command field holds the name of the command to be invoked as a string.
36
+ The invocation id field holds an identifier which will be repeated by the backend's response.
37
+
38
+ {
39
+ "type": "request",
40
+ "command": <command>,
41
+ "invocation_id": <invocation_id>
42
+ ...
43
+ }
44
+
45
+ == Response Messages
46
+
47
+ The response message repeats the invocation id of the request it replies to.
48
+ If the requested command is not known by the backend, it will respond with a
49
+ "unknonw_command_error" message instead (see below).
50
+
51
+ {
52
+ "type": "response",
53
+ "invocation_id": <invocation_id>
54
+ ...
55
+ }
56
+
57
+ == Error Messages
58
+
59
+ There are a number of error message which may be sent in response to a request message.
60
+
61
+ === Unknown Command Error
62
+
63
+ {
64
+ "type": "unknown_command_error",
65
+ "invocation_id": <invocation_id>,
66
+ "command": <unknown command [string]>
67
+ }
68
+
69
+ == Progress Information
70
+
71
+ Before the actual response is sent, the backend may send progress information.
72
+ This is useful whenever a command takes a longer time to complete.
73
+ Frontends should be prepared to receive progress information messages for any command.
74
+ They may however choose to ignore this information, i.e. not display any progress to the user.
75
+
76
+ {
77
+ "type": "progress",
78
+ "invocation_id": <invocation_id [integer]>,
79
+ "percentage": <percentage [integer][0..100]>,
80
+ "message": <message [string]>
81
+ }
82
+
83
+ The percentage and message fields are optional.
84
+ If percentage is present, the frontend should display a progress bar, otherwise it should just
85
+ indicate to the user that a job is ongoing.
86
+ The message field may carry information about the currently ongoing subtask.
87
+
88
+ == Commands
89
+
90
+ For each command, the layout of the request and response messages will be given below.
91
+ Note that the invocation id field is present in every request and response but is omitted for brevity.
92
+
93
+
94
+ === Load Model
95
+
96
+ This command requests the backend to load or reload the model.
97
+
98
+ {
99
+ "type": "request",
100
+ "command": "load_model"
101
+ }
102
+
103
+ The response may indicate problems which were detected during loading.
104
+ In order to reduce the size of the response message, problems are grouped by file.
105
+ The ``total_problems`` field is used to indicate the total number of problems which may be lower
106
+ than the number actually returned. If the total number of problems is unknown, ``total_problems``
107
+ should be set to -1. This may be the case when problem detection is interrupted in order to
108
+ limit detection effort and/or response time.
109
+
110
+ {
111
+ "type": "response"
112
+ "total_problems": <number of total problems or -1 [integer]>,
113
+ "problems": [
114
+ {
115
+ "file": <fully qualifed file name [string]>,
116
+ "problems: [
117
+ {
118
+ "message": <message [string]>,
119
+ "severity": <['debug', 'info', 'warn', 'error', 'fatal']>,
120
+ "line": <line number [integer]>
121
+ }
122
+ ...
123
+ ]
124
+ }
125
+ ...
126
+ ]
127
+ }
128
+
129
+ === Content Complete
130
+
131
+ This command is a request by the frontend in order to show content completion options at a given
132
+ location within a file. The location is expressed using a set of context lines and the cursor
133
+ column position in the current line. See section "Context Extraction" for details about how to
134
+ build the set of context lines in the frontend. Column number start at 1.
135
+
136
+ {
137
+ "type": "request",
138
+ "command": "content_complete",
139
+ "context": <context lines [array of string]>,
140
+ "column": <cursor column [integer]>
141
+ }
142
+
143
+ The backend replies with a list of completion options.
144
+ The field ``insert`` holds the text to be inserted if the completion option is chosen.
145
+ The field ``display`` contains the string which should be displayed to the user in some kind of
146
+ completion option menu. An optional description field may provide more information about a
147
+ particular option.
148
+
149
+ If there are no completion options, the backend may send an empty response.
150
+
151
+ {
152
+ "type": "response",
153
+ "options": [
154
+ {
155
+ "display": <text to display [string]>,
156
+ "insert": <text to be inserted [string]>,
157
+ "desc": <optional description [string]>
158
+ }
159
+ ]
160
+ }
161
+
162
+ === Link Targets
163
+
164
+ This command is issued by the frontend when the user tries to follow a hyperlink, e.g. following a model reference.
165
+ The frontend needs to send the context as described in section "Context Extraction" and the
166
+ column where the cursor (e.g. the mouse pointer, or an actual text cursor) is placed.
167
+ Column numbers start at 1.
168
+
169
+ {
170
+ "type": "request",
171
+ "command": "link_targets",
172
+ "context": <context lines [array of string]>,
173
+ "column": <cursor column [integer]>
174
+ }
175
+
176
+ The backend analyses the text at the cursor position in order to find out if a link is present.
177
+ If so, it sends back the columns of the beginning and the end of the link as well as the actual
178
+ link targets. Column positions are inclusive, i.e. the beginning and the end column are part of
179
+ the link. Link targets contain the string to be displayed to the user, the filename and the line
180
+ number within the file.
181
+ An optional description field may provide more information about a particular lin target.
182
+
183
+ If there is no link, the backend may send an empty response.
184
+
185
+ {
186
+ "type": "response",
187
+ "begin_column": <begin column of hyperlink [integer]>,
188
+ "end_column": <end column of hyperlink [integer]>,
189
+ "targets": [
190
+ {
191
+ "display": <display name [string]>,
192
+ "file": <fully qualified file name [string]>,
193
+ "line": <line number [integer]>,
194
+ "desc": <optional description [string]>
195
+ }
196
+ ...
197
+ ]
198
+ }
199
+
200
+ === Find Elements
201
+
202
+ This command is used to search for elements within the model. The frontend should allow the user
203
+ to enter an arbitrary search pattern as a string. This search pattern is sent to the backend
204
+ which actually defines how the pattern is interpreted.
205
+
206
+ {
207
+ "type": "request",
208
+ "command": "find_elements",
209
+ "search_pattern": <search pattern [string]>
210
+ }
211
+
212
+ The backend responds by sending the total number of elements found and a list of elements
213
+ together with their file and line information.
214
+ Note that the number of elements actually returned may be lower than the total number.
215
+ If the total number of elements is unknown ``total_elements`` should be set to -1.
216
+ This allows to truncate large search result sets and still provide the user with the number of
217
+ elements which were omitted or at least with the fact that the result set has been truncated.
218
+ An optional description field my provide more information about a particular element.
219
+
220
+ If there are no search results, the backend may send an empty response.
221
+
222
+ {
223
+ "type": "response",
224
+ "total_elements": <total number of elements or -1 [string]>,
225
+ "elements": [
226
+ {
227
+ "display": <display name [string]>,
228
+ "file": <fully qualified file name [string]>,
229
+ "line": <line number [integer]>,
230
+ "desc": <optional description [string]>
231
+ }
232
+ ...
233
+ ]
234
+ }
235
+
236
+ === Context Information
237
+
238
+ This command is used by the frontend to request information about a particular position in
239
+ a file. The frontend will send the current context (section "context extraction") and the cursor
240
+ column. If for example, the context information is to be shown as a hover at the position of the
241
+ mouse pointer, the context and column need to be calculated at the position of the mouse pointer,
242
+ not the position of the text cursor.
243
+
244
+ {
245
+ "type": "request",
246
+ "command": "context_info",
247
+ "context": <context lines>,
248
+ "column": <cursor column>
249
+ }
250
+
251
+ The backend reponds by sending the textual description to be shown to the user.
252
+
253
+ {
254
+ "type": "response",
255
+ "desc": <textual description>
256
+ }
257
+
258
+ === Custom Commands
259
+
260
+ This command is used to retrieve a list of custom commands understood by the backend.
261
+ These commands may be available in a specific context only. If the frontend includes context
262
+ and column information in the request, the backend will list only commands applicable in that
263
+ context. If the context information is omitted, the backend will return all commands applicable
264
+ without any specific context.
265
+
266
+ Note that even for commands without context information, the frontend should repeat to request
267
+ the command list as the list of available commands may change. For example, the command list could
268
+ be requested everytime the user gets a chance to choose from a command menu.
269
+
270
+ {
271
+ "type": "request",
272
+ "command": "custom_commands"
273
+ "context": <context lines, optional>,
274
+ "column": <cursor column, optional>
275
+ }
276
+
277
+ The backend responds by a list of commands which may be categorized into a tree structure.
278
+ This information can be used to show the commands in a hierarchical menu, e.g. a context menu.
279
+
280
+ {
281
+ "type": "response",
282
+ "entries": [
283
+ {
284
+ "type": "category",
285
+ "name": <display name>,
286
+ "entries": [
287
+ {
288
+ "type": "command",
289
+ "name": <display name>,
290
+ "id": <command identifier>
291
+ }
292
+ ...
293
+ ]
294
+ }
295
+ ...
296
+ ]
297
+ }
298
+
299
+ === Custom Command Invocation
300
+
301
+ Custom commands are invoked just like the predefined commands. The frontend uses the command
302
+ identifier returned by the "Custom Commands" request as the value of the ``command`` field in
303
+ the new invocation request. If the command id was returned by a "Costum Commands" request which
304
+ included context information, the frontend should send the same context information in the new
305
+ invocation request and all repeated requests (see below). If this information was not present
306
+ in command list request, it should not be send in the new command invocation.
307
+
308
+ {
309
+ "type": "request",
310
+ "command": <command id>
311
+ }
312
+
313
+ On first invocation, the frontend will not send any parameters with the command request.
314
+ Instead, the backend's response may ask for parameters to be included into the next request.
315
+ In this case, the frontend should will prompt the user to enter the required information and then
316
+ reinvoke the command with the parameters included. This process of asking for more parameters
317
+ may be repeated several times.
318
+
319
+ More generally, the backend will tell the frontend to display dialogs to the user.
320
+ Dialogs may contain input fields, output fields and hidden fields.
321
+ Fields may be marked to indicate that their value should be sent to the backend on next invocation.
322
+
323
+ The dialogs contain elements of certain types:
324
+
325
+ * text: text as a string
326
+ * text
327
+ * element_list field
328
+ * element_table field
329
+
330
+ Each dialog element has the following attributes:
331
+
332
+ * name: user visible title of the field [String]
333
+ * desc: an optional description of the field [String]
334
+ * editable: if the user can edit the field [Boolean]
335
+ * visible: if the field is visible, there may be hidden fields for internal purpose [Boolean]
336
+ * return: if the value should be sent back with the next request [Boolean]
337
+ * error: an error description, if present the field should be marked to have an error [String]
338
+ * value: the preset value of the field, type is field type specific
339
+
340
+ The frontend should keep repeating requests as long as the field ``repeat`` is set to ``true``.
341
+
342
+ {
343
+ "type": "response",
344
+ "repeat": <if command should be repeated>,
345
+ "dialog": {
346
+ "title": <dialog title>,
347
+ "desc": <description what to do>,
348
+ "elements": [
349
+ {
350
+ "type": "text_input",
351
+ "name": <parameter name>,
352
+ "value": <preset value>,
353
+ "error": <error text>
354
+ },
355
+ {
356
+ "type": "choice_input",
357
+ "num_min": <min number of elements to choose, default: 1>,
358
+ "num_max": <max mumber of elements to choose, default: 1>,
359
+ "choices": [
360
+ "display": <display name>,
361
+ "id": <identifier to be sent back>,
362
+ ],
363
+ "value": [ <selected choice>, <selected choice>, ...],
364
+ "error": <error text>
365
+ },
366
+ {
367
+ "type": "element_input",
368
+ "num_min": <min number of elements to choose, default: 1>,
369
+ "num_max": <max mumber of elements to choose, default: 1>,
370
+ "choices": [
371
+ {
372
+ "display": <display name>,
373
+ "id": <identifier to be sent back>,
374
+ "file": <fully qualfied file name, optional>,
375
+ "line": <line number, optional>,
376
+ "ancestors": <parent hierarchy, optional",
377
+ }
378
+ ...
379
+ ],
380
+ "value": [ <selected choice>, <selected choice>, ...],
381
+ "error": <error text>
382
+ }
383
+ ]
384
+ }
385
+ }
386
+
387
+ === Stop Service
388
+
389
+ This command is normally invoked when the frontend terminates or otherwise needs to terminate
390
+ the backend service. When receiving this command, the backend should terminate.
391
+
392
+ {
393
+ "type": "request",
394
+ "command": "stop"
395
+ }
396
+
397
+ Before actually stopping, the backend should send an empty response.
398
+
399
+ {
400
+ "type": "response"
401
+ }
402
+
403
+ == Context Extraction
404
+
405
+ Context lines are lines from an RText file which contain a (context) command and all
406
+ the parent commands wrapped around it. Any sibling commands can be omitted as well as
407
+ any lines containing closing braces and brackets. The order of lines is the same as in the
408
+ RText file.
409
+
410
+ Here is an example. Consider the following RText file with the cursor in the line of "Command3"
411
+ at the time when the auto completion command is issued.
412
+
413
+ Command1 {
414
+ Command2 {
415
+ Command 3 {
416
+ Command 4
417
+ }
418
+ role1: [
419
+ Command5 <== cursor in this line
420
+ Command6
421
+ ]
422
+ }
423
+ Command7
424
+ }
425
+
426
+ The context lines in this case would be the following.
427
+
428
+ Command1 {
429
+ Command2 {
430
+ role1: [
431
+ Command5
432
+
433
+ The current line is always the last of the context lines.
434
+
435
+ See RText::Frontend::Context::extract for a concise implementation of the required algorithm.
436
+
437
+ Note that all siblings of the command and parent commands have been stripped off, as well as
438
+ any closing braces or brackets.
439
+
440
+ The purpose of this special context line format is to keep the task of extracting the
441
+ context in the frontend simple and the amount of data transmitted to the backend low.
442
+ It's also a way to keep the parsing time of the context low in the backend and thus to minimize
443
+ the user noticable delay.
444
+