rtext 0.4.0 → 0.5.0

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