You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: contributor-book/plugin_protocol_reference.md
+236-9
Original file line number
Diff line number
Diff line change
@@ -25,6 +25,8 @@ Typical plugin interaction after the initial handshake looks like this:
25
25
26
26
The plugin **should** respond to further plugin calls. The engine **may** send additional plugin calls before responses have been received, and it is up to the plugin to decide whether to handle each call immediately as it is received, or to process only one at a time and hold on to them for later. In any case, sending another plugin call before a response has been received **should not** cause an error.
27
27
28
+
The plugin **may** send [engine calls](#enginecall) during the execution of a call to request operations from the engine. Engine calls are [only valid within the context of a call](#enginecall-context) and may not be sent otherwise.
29
+
28
30
The engine **may** send a [`Goodbye`](#goodbye) message to the plugin indicating that it will no longer send any more plugin calls. Upon receiving this message, the plugin **may** choose not to accept any more plugin calls, and **should** exit after any in-progress plugin calls have finished.
29
31
30
32
## `Hello`
@@ -79,12 +81,11 @@ Example:
79
81
80
82
Tell the plugin to run a command. The argument is the following map:
|**name**| string | The name of the command to run |
87
+
|**call**|[`EvaluatedCall`](#evaluatedcall)| Information about the invocation, including arguments |
88
+
|**input**|[`PipelineDataHeader`](#pipelinedataheader)| Pipeline input to the command |
88
89
89
90
<aname="evaluatedcall"></a>
90
91
@@ -177,6 +178,77 @@ There is currently one supported operation: `ToBaseValue`, which **should** retu
177
178
}
178
179
```
179
180
181
+
### `EngineCallResponse`
182
+
183
+
A response to an [engine call](#enginecall) made by the plugin. The argument is a 2-tuple (array): (`engine_call_id`, `engine_call`)
184
+
185
+
The `engine_call_id` refers to the same number that the engine call being responded to originally contained. The plugin **must** send unique IDs for each engine call it makes. Like [`CallResponse`](#callresponse), there are multiple types of responses:
186
+
187
+
#### `Error` engine call response
188
+
189
+
A failure result. Contains a [`ShellError`](#shellerror).
190
+
191
+
Example:
192
+
193
+
```json
194
+
{
195
+
"EngineCallResponse": [
196
+
0,
197
+
{
198
+
"Error": {
199
+
"IOError": {
200
+
"msg": "The connection closed."
201
+
}
202
+
}
203
+
}
204
+
]
205
+
}
206
+
```
207
+
208
+
#### `PipelineData` engine call response
209
+
210
+
A successful result with a Nu [`Value`](#value) or stream. The body is a [`PipelineDataHeader`](#pipelinedataheader).
211
+
212
+
Example:
213
+
214
+
```json
215
+
{
216
+
"EngineCallResponse": [
217
+
0,
218
+
{
219
+
"ListStream": {
220
+
"id": 23
221
+
}
222
+
}
223
+
]
224
+
}
225
+
```
226
+
227
+
#### `Config` engine call response
228
+
229
+
A successful result of a [`Config` engine call](#config-engine-call). The body is a [`Config`](#config).
230
+
231
+
Example:
232
+
233
+
```json
234
+
{
235
+
"EngineCallResponse": [
236
+
0,
237
+
{
238
+
"Config": {
239
+
"external_completer": null,
240
+
"filesize_metric": true,
241
+
"table_mode": "Rounded",
242
+
"table_move_header": false,
243
+
...
244
+
}
245
+
}
246
+
]
247
+
}
248
+
```
249
+
250
+
This example is abbreviated, as the [`Config`](#config) object is large and ever-changing.
251
+
180
252
### `Goodbye`
181
253
182
254
Indicate that no further plugin calls are expected, and that the plugin **should** exit as soon as it is finished processing any in-progress plugin calls.
@@ -225,7 +297,7 @@ Example:
225
297
}
226
298
```
227
299
228
-
### `Signature` plugin call response
300
+
####`Signature` plugin call response
229
301
230
302
A successful response to a [`Signature` plugin call](#signature-plugin-call). The body is an array of [signatures](https://docs.rs/nu-protocol/0.90.1/nu_protocol/struct.PluginSignature.html).
231
303
@@ -275,9 +347,9 @@ Example:
275
347
}
276
348
```
277
349
278
-
### `PipelineData` plugin call response
350
+
####`PipelineData` plugin call response
279
351
280
-
A successful result with a Nu [`Value`](#value) or stream. The body is a map: see [`PipelineDataHeader`](#pipelinedataheader).
352
+
A successful result with a Nu [`Value`](#value) or stream. The body is a [`PipelineDataHeader`](#pipelinedataheader).
281
353
282
354
Example:
283
355
@@ -300,6 +372,113 @@ Example:
300
372
}
301
373
```
302
374
375
+
### `EngineCall`
376
+
377
+
Plugins can make engine calls during execution of a [call](#call). The body is a map with the following keys:
|**context**| integer | The ID of the [call](#call) that this engine call relates to. |
382
+
|**id**| integer | A unique ID for this engine call, in order to send the [response](#enginecallresponse). |
383
+
|**call**|`EngineCall`| One of the options described below. |
384
+
385
+
<aname="enginecall-context"></a>
386
+
387
+
The context **must** be an ID of a [call](#call) that was received that is currently in one of two states:
388
+
389
+
1. The [response](#callresponse) has not been sent yet.
390
+
2. The response contained stream data (i.e. [`ListStream`](#pipelinedataheader-liststream) or [`ExternalStream`](#pipelinedataheader-externalstream)), and at least one of the streams started by the response is still sending data (i.e. [`End`](#end) has not been sent).
391
+
392
+
After a response has been fully sent, and streams have ended, the `context` from that call can no longer be used.
393
+
394
+
The engine call ID **must** be unique for the lifetime of the plugin, and it is suggested that this be a sequentially increasing number across all engine calls made by the plugin. It is not separated by `context`; the response only contains the `id`.
395
+
396
+
#### `GetConfig` engine call
397
+
398
+
Get the Nushell engine configuration. Returns a [`Config` response](#config-engine-call-response) if
399
+
successful.
400
+
401
+
Example:
402
+
403
+
```json
404
+
{
405
+
"EngineCall": {
406
+
"context": 0,
407
+
"id": 0,
408
+
"call": "GetConfig"
409
+
}
410
+
}
411
+
```
412
+
413
+
#### `GetPluginConfig` engine call
414
+
415
+
Get the configuration for the plugin, from its section in `$env.config.plugins.NAME` if present. Returns a [`PipelineData` response](#pipelinedata-engine-call-response) if successful, which will contain either a [`Value`](#pipelinedataheader-value) or be [`Empty`](#pipelinedataheader-empty) if there is no configuration for the plugin set.
416
+
417
+
If the plugin configuration was specified as a closure, the engine will evaluate that closure and return the result, which may cause an [error response](#error-engine-call-response).
418
+
419
+
Example:
420
+
421
+
```json
422
+
{
423
+
"EngineCall": {
424
+
"context": 3,
425
+
"id": 8,
426
+
"call": "GetPluginConfig"
427
+
}
428
+
}
429
+
```
430
+
431
+
#### `EvalClosure` engine call
432
+
433
+
Pass a [`Closure`](#closure) and arguments to the engine to be evaluated. Returns a [`PipelineData` response](#pipelinedata-engine-call-response) if successful with the output of the closure, which may be a stream.
|**closure**|`Spanned`<[`Closure`](#closure)> | The closure to call, generally from a [`Value`](#value). |
438
+
|**positional**|[`Value`](#value) array | Positional arguments for the closure. |
439
+
|**input**|[`PipelineDataHeader`](#pipelinedataheader)| Input for the closure. |
440
+
|**redirect_stdout**| boolean | Whether to redirect stdout if the closure ends in an external command. |
441
+
|**redirect_stderr**| boolean | Whether to redirect stderr if the closure ends in an external command. |
442
+
443
+
Example:
444
+
445
+
```json
446
+
{
447
+
"EngineCall": {
448
+
"context": 7,
449
+
"id": 40,
450
+
"call": {
451
+
"EvalClosure": {
452
+
"closure": {
453
+
"item": {
454
+
"block_id": 72,
455
+
"captures": []
456
+
},
457
+
"span": {
458
+
"start": 780,
459
+
"end": 812
460
+
}
461
+
},
462
+
"positional": [
463
+
{
464
+
"Int": {
465
+
"val": 7,
466
+
"span": {
467
+
"start": 3080,
468
+
"end": 3081
469
+
}
470
+
}
471
+
}
472
+
],
473
+
"input": "Empty",
474
+
"redirect_stdout": true,
475
+
"redirect_stderr": false
476
+
}
477
+
}
478
+
}
479
+
}
480
+
```
481
+
303
482
## Stream messages
304
483
305
484
Streams can be sent by both the plugin and the engine. The agent that is sending the stream is known as the _producer_, and the agent that receives the stream is known as the _consumer_.
This enum describes errors produced by the engine. As this enum is quite large and grows frequently, it is recommended to try to send this back to the engine without interpreting it, if possible.
This struct describes the configuration of Nushell. It is quite large and frequently changing, so please refer to the Rust documentation if there is anything you need from it.
This is the representation of a closure within the engine, which references a block ID and a list of captures with variable IDs and their contents. It may be contained within [`Value`](#value).
832
+
833
+
The plugin **should not** try to inspect the contents of the closure. It is recommended that this is only used as an argument to the [`EvalClosure` engine call](#evalclosure-engine-call). The exact representation of a closure is likely to change in the future to avoid serializing all of the captures.
0 commit comments