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: book/plugins.md
+3-8Lines changed: 3 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
Nu can be extended using plugins. Plugins behave much like Nu's built-in commands, with the added benefit that they can be added separately from Nu itself.
4
4
5
-
Nu plugins are executables; Nu launches them as needed and communicates with them over [stdin, stdout, and stderr](https://en.wikipedia.org/wiki/Standard_streams). Nu plugins can use either JSON or MSGPACK as their communication encoding.
5
+
Nu plugins are executables; Nu launches them as needed and communicates with them over [stdinand stdout](https://en.wikipedia.org/wiki/Standard_streams) or [local sockets](https://en.wikipedia.org/wiki/Inter-process_communication). Nu plugins can use either [JSON](https://www.json.org/) or [MessagePack](https://msgpack.org/) as their communication encoding.
6
6
7
7
## Downloading and installing a plugin
8
8
@@ -54,14 +54,9 @@ Windows:
54
54
> register .\my_plugins\nu_plugin_cool.exe
55
55
```
56
56
57
-
When [`register`](/commands/docs/register.md) is called:
57
+
When registering a plugin, Nu runs it in order to ensure compatibility and to get a list of all of the commands it supports. These are then saved to the plugin file (`$nu.plugin-path`) which acts as a cache.
58
58
59
-
1. Nu launches the plugin, and waits for the plugin to tell Nu which communication encoding it should use
60
-
2. Nu sends it a "Signature" message over stdin
61
-
3. The plugin responds via stdout with a message containing its signature (name, description, arguments, flags, and more)
62
-
4. Nu saves the plugin signature in the file at `$nu.plugin-path`, so registration is persisted across multiple launches
63
-
64
-
Once registered, the plugin is available as part of your set of commands:
59
+
Once registered, the plugin should show up in [`plugin list`](/commands/docs/plugin_list.md) and all of its commands are available in scope:
Nu plugins **must** be an executable file with a filename starting with `nu_plugin_`. All interaction with the plugin is handled over standard input (stdin) and output (stdout). Standard error (stderr) is not redirected, and can be used by the plugin to print messages directly.
9
+
Nu plugins **must** be an executable file with a filename starting with `nu_plugin_`. Plugins can run in one of two modes:
10
10
11
-
Plugins are always passed `--stdio` as a command line argument. Other command line arguments are reserved for options that might be added in the future, including other communication methods. Plugins that support the protocol as described in this document **should** reject other arguments and print an informational message to stderr.
11
+
1. Stdio mode, which **must** be supported. The plugin is passed `--stdio` as a command line argument. All interaction with the plugin is handled over standard input (stdin) and output (stdout). Standard error (stderr) is not redirected, and can be used by the plugin to print messages directly.
12
+
13
+
2. Local socket mode, which **may** be supported (advertised via the [`LocalSocket` feature](#localsocket-feature)). The plugin is passed `--local-socket` as the first command line argument, and then the path of the Unix domain socket or name of the Windows named pipe to use for communication. None of the standard input or output streams are redirected, and they may all be used to interact with the user's terminal. See the [documentation](#localsocket-feature) specific to the feature for more details.
14
+
15
+
Other command line arguments are reserved for options that might be added in the future, including other communication methods. Plugins that support the protocol as described in this document **should** reject other arguments and print an informational message to stderr.
12
16
13
17
Immediately after spawning a plugin, Nu expects the plugin to send its encoding type. Currently two encoding types are supported: [`json`](#json) and [`msgpack`](#messagepack). The desired encoding type **should** be sent first with the length of the string as a single byte integer and then the encoding type string. That is, with C-like escape syntax, `"\x04json"` or `"\x07msgpack"`. In this document, the JSON format will be used for readability, but the MessagePack format is largely equivalent. See the [Encoding](#encoding) section for specific intricacies of the formats.
14
18
15
19
Nu will then send messages in the desired encoding. The first message is always [`Hello`](#hello). The plugin **must** send a `Hello` message indicating the expected Nu version that it is compatible with, and any supported protocol features. The engine will also send a `Hello` message with its version, and any supported protocol features. The plugin **may** verify that it is compatible with the Nu version provided by the engine, but the engine will end communication with a plugin if it is determined to be unsupported. The plugin **must not** use protocol features it supports if they are not also confirmed to be supported by the engine in its `Hello` message. It is not permitted to send any other messages before sending `Hello`.
16
20
17
-
The plugin **should** then receive and respond to messages until its stdin is closed.
21
+
The plugin **should** then receive and respond to messages until its input stream is closed.
18
22
19
23
Typical plugin interaction after the initial handshake looks like this:
20
24
@@ -41,8 +45,6 @@ After the encoding type has been decided, both the engine and plugin **must** se
41
45
42
46
To be accepted, the `version` specified **must** be [semver](https://semver.org) compatible with the engine's version. "0.x.y" and "x.y.z" for differing values of "x" are considered to be incompatible.
43
47
44
-
There are currently no protocol features defined, and they are only likely to be used once Nu releases versions after stabilization at "1.0.0".
45
-
46
48
Plugins **may** decide to refuse engine versions with more strict criteria than specified here.
47
49
48
50
Example:
@@ -57,6 +59,34 @@ Example:
57
59
}
58
60
```
59
61
62
+
### Features
63
+
64
+
All features are maps that **must** contain at least a `name` key, and **may** contain other keys. Features that are not recognized by `name`**must** be ignored, and not cause an error. Plugins **must** only advertise support for features they implement, and **should not** determine the features they will advertise depending on the engine's `Hello` message.
65
+
66
+
#### `LocalSocket` feature
67
+
68
+
This feature advertises support for local socket communication, instead of stdio.
69
+
70
+
Example:
71
+
72
+
```json
73
+
{
74
+
"name": "LocalSocket"
75
+
}
76
+
```
77
+
78
+
When local socket communication is advertised to an engine supporting the feature, the engine will cease stdio communication and launch the plugin again with the `--local-socket` command line argument. The second argument is either a path to a Unix domain socket on Linux, Android, macOS, and other Unix-like operating systems, or the name of a named pipe (without the `\\.\pipe\` prefix) on Windows.
79
+
80
+
In either case, during startup, the plugin is expected to establish two separate connections to the socket, in this order:
81
+
82
+
1. The input stream connection, used to send messages from the engine to the plugin
83
+
2. The output stream connection, used to send messages from the plugin to the engine
84
+
85
+
The connections are separate in order to facilitate ownership of the streams by separate threads. After these connections are both established, the engine will remove the socket, and will not accept further connections.
86
+
87
+
If local socket communication fails to initialize, the engine will abort, stop the plugin, and start it again with the stdio mode, even if the plugin supports local sockets. Whether local socket mode initialized successfully, and therefore the plugin is allowed to use stdio, can be observed when
88
+
[`EngineInterface::is_using_stdio()`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.is_using_stdio) returns `false` for Rust plugins.
89
+
60
90
## Input messages
61
91
62
92
These are messages sent from the engine to the plugin. [`Hello`](#hello) and [`Stream messages`](#stream-messages) are also included.
@@ -806,6 +836,48 @@ Example:
806
836
}
807
837
```
808
838
839
+
#### `EnterForeground` engine call
840
+
841
+
Moves the plugin to the foreground group for direct terminal access, in an operating system-defined manner. This should be called when the plugin is going to drive the terminal in raw mode, for example to implement a terminal UI. It will likely be necessary for the plugin to also be running in [local socket mode](#localsocket-feature) in that case.
842
+
843
+
This call responds with [`Empty` pipeline data](#pipelinedataheader-empty) on success when no action is required by the plugin. On Unix-like operating systems, if the response is [`Value` pipeline data](#pipelinedataheader-value), it contains an [`Int`](#int) which is the process group ID the plugin must join using `setpgid()` in order to be in the foreground.
844
+
845
+
This call will fail with an error if the plugin is already in the foreground.
846
+
847
+
The plugin **should** call [`LeaveForeground`](#leaveforeground-engine-call) when it no longer needs to be in the foreground. Note that the plugin will also automatically be removed from the foreground when the plugin call response is received, even if the plugin call returns a stream.
848
+
849
+
Example:
850
+
851
+
```json
852
+
{
853
+
"EngineCall": {
854
+
"context": 0,
855
+
"id": 0,
856
+
"call": "EnterForeground"
857
+
}
858
+
}
859
+
```
860
+
861
+
#### `LeaveForeground` engine call
862
+
863
+
Resets the state set by [`EnterForeground`](#enterforeground-engine-call).
864
+
865
+
If the plugin had been requested to change process groups by the response of `EnterForeground`, it should also reset that state by calling `setpgid(0)`, since plugins are normally in their own process group.
866
+
867
+
This call responds with [`Empty` pipeline data](#pipelinedataheader-empty) on success.
868
+
869
+
Example:
870
+
871
+
```json
872
+
{
873
+
"EngineCall": {
874
+
"context": 0,
875
+
"id": 0,
876
+
"call": "LeaveForeground"
877
+
}
878
+
}
879
+
```
880
+
809
881
#### `EvalClosure` engine call
810
882
811
883
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.
Copy file name to clipboardExpand all lines: contributor-book/plugins.md
+5-3Lines changed: 5 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ title: Plugins
6
6
7
7
## Protocol
8
8
9
-
Plugins are executable applications that communicate with Nu by exchanging serialized data over stdin and stdout (much in the same way VSCode plugins do). The protocol is split into two stages.
9
+
Plugins are executable applications that communicate with Nu by exchanging serialized data over a stream (much in the same way VSCode plugins do). The stream may either be stdio, which all plugins support, or a local socket (e.g. Unix domain socket or Windows named pipe) when supported. The protocol is split into two stages.
10
10
11
11
The first stage of the protocol deals with the initial discovery of the plugin. When a plugin is registered the plugin is executed and asked to reply with its configuration. Just as with commands, plugins have a signature that they respond to Nu with. Once Nu has this signature, it knows how to later invoke the plugin to do work.
12
12
@@ -20,7 +20,9 @@ Nu keeps a registry of plugins at the file system location defined by configurat
20
20
21
21
## Launch environment
22
22
23
-
Stdin and stdout are redirected for use in the plugin protocol, and must not be used for other purposes. Stderr is inherited, and may be used to print to the terminal.
23
+
When launched in `stdio` mode, `stdin` and `stdout` are redirected for use in the plugin protocol, and must not be used for other purposes. Stderr is inherited, and may be used to print to the terminal.
24
+
25
+
When launched in `local-socket` mode, `stdin` and `stdout` can also be used to interact with the user's terminal. This is the default for Rust plugins unless `local-socket` is disabled, and can be checked for by calling [`EngineInterface::is_using_stdio()`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.is_using_stdio). Plugins may fall back to `stdio` mode if sockets are not working for some reason, so it is important to check this if you are going to be using `stdin` or `stdout`.
24
26
25
27
Environment variables set in the shell are set in the environment of a plugin when it is launched from a plugin call.
26
28
@@ -791,7 +793,7 @@ Ordinarily, Nu will execute the plugin and knows what data to pass to it and how
791
793
792
794
We recommend keeping the [plugin protocol](plugin_protocol_reference.md) documentation handy as a reference while reading this section.
793
795
794
-
Assuming you've built the Rust plugin described above let's now run it:
796
+
Assuming you've built the Rust plugin described above let's now run it with `--stdio` so that it communicates with us there:
0 commit comments