diff --git a/README.md b/README.md index ef5d8ee..f436982 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ # nu_plugin_dbus +[Nushell](https://nushell.sh/) plugin for interacting with [D-Bus](https://dbus.freedesktop.org/) + +With the commands provided by this plugin, you can interact with many of the desktop-oriented +systems on UNIX-like systems that use D-Bus, including Linux and FreeBSD. You can control media +players, on-screen displays, power policies, and even administer services. + +Nushell provides a particularly nice environment for interacting with D-Bus, as both support typed +structured data, and interacting with this on a traditional UNIX command line with tools like +`dbus-send` and `busctl` is cumbersome and tricky to automate. + +This plugin automatically determines the correct input types through D-Bus introspection when +available, unlike either of the aforementioned tools, making it easier to interact with objects on +the bus without having to implement boilerplate from documentation. + ## Install with Cargo Run: `cargo install --locked nu_plugin_dbus` @@ -18,49 +32,15 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi Subcommands: dbus call - Call a method and get its response dbus get - Get a D-Bus property - dbus get-all - Get all D-Bus property for the given objects + dbus get-all - Get all D-Bus properties for the given object dbus introspect - Introspect a D-Bus object dbus list - List all available connection names on the bus - dbus set - Get all D-Bus property for the given objects + dbus set - Set a D-Bus property Flags: -h, --help - Display the help message for this command -## `dbus introspect` - - Introspect a D-Bus object - - Returns information about available nodes, interfaces, methods, signals, and properties on the given object path - - Search terms: dbus - - Usage: - > dbus introspect {flags} - - Flags: - -h, --help - Display the help message for this command - --session - Send to the session message bus (default) - --system - Send to the system message bus - --started - Send to the bus that started this process, if applicable - --bus - Send to the bus server at the given address - --peer - Send to a non-bus D-Bus server at the given address. Will not call the Hello method on initialization. - --timeout - How long to wait for a response - --dest (required parameter) - The name of the connection that owns the object - - Parameters: - object : The path to the object to introspect - - Examples: - Look at the MPRIS2 interfaces exposed by Spotify - > dbus introspect --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 | explore - - Get methods exposed by KDE Plasma's on-screen display service - > dbus introspect --dest=org.kde.plasmashell /org/kde/osdService | get interfaces | where name == org.kde.osdService | get 0.methods - - List objects exposed by KWin - > dbus introspect --dest=org.kde.KWin / | get children | select name - -## `dbus call` +# `dbus call` Call a method and get its response @@ -92,6 +72,13 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi method : The name of the method to send ...args : Arguments to send with the method call + Input/output types: + ╭───┬─────────┬────────╮ + │ # │ input │ output │ + ├───┼─────────┼────────┤ + │ 0 │ nothing │ any │ + ╰───┴─────────┴────────╯ + Examples: Ping the D-Bus server itself > dbus call --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Peer Ping @@ -99,7 +86,7 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi Show a notification on the desktop for 5 seconds > dbus call --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications Notify "Floppy disks" 0 "media-floppy" "Rarely seen" "But sometimes still used" [] {} 5000 -## `dbus get` +# `dbus get` Get a D-Bus property @@ -123,6 +110,13 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi interface : The name of the interface the property belongs to property : The name of the property to read + Input/output types: + ╭───┬─────────┬────────╮ + │ # │ input │ output │ + ├───┼─────────┼────────┤ + │ 0 │ nothing │ any │ + ╰───┴─────────┴────────╯ + Examples: Get the currently playing song in Spotify > dbus get --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player Metadata @@ -133,9 +127,9 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi │ xesam:url │ https://open.spotify.com/track/51748BvzeeMs4PIdPuyZmv │ ╰──────────────┴───────────────────────────────────────────────────────╯ -## `dbus get-all` +# `dbus get-all` - Get all D-Bus property for the given objects + Get all D-Bus properties for the given object Search terms: dbus @@ -156,6 +150,13 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi object : The path to the object to read the property from interface : The name of the interface the property belongs to + Input/output types: + ╭───┬─────────┬────────╮ + │ # │ input │ output │ + ├───┼─────────┼────────┤ + │ 0 │ nothing │ record │ + ╰───┴─────────┴────────╯ + Examples: Get the current player state of Spotify > dbus get-all --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player @@ -165,14 +166,16 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi │ PlaybackStatus │ Paused │ ╰────────────────┴────────╯ -## `dbus set` +# `dbus introspect` + + Introspect a D-Bus object - Get all D-Bus property for the given objects + Returns information about available nodes, interfaces, methods, signals, and properties on the given object path Search terms: dbus Usage: - > dbus set {flags} + > dbus introspect {flags} Flags: -h, --help - Display the help message for this command @@ -182,22 +185,29 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi --bus - Send to the bus server at the given address --peer - Send to a non-bus D-Bus server at the given address. Will not call the Hello method on initialization. --timeout - How long to wait for a response - --signature - Signature of the value to set, in D-Bus format. - If not provided, it will be determined from introspection. - If --no-introspect is specified and this is not provided, it will be guessed (poorly) - --dest (required parameter) - The name of the connection to write the property on + --dest (required parameter) - The name of the connection that owns the object Parameters: - object : The path to the object to write the property on - interface : The name of the interface the property belongs to - property : The name of the property to write - value : The value to write to the property + object : The path to the object to introspect + + Input/output types: + ╭───┬─────────┬────────╮ + │ # │ input │ output │ + ├───┼─────────┼────────┤ + │ 0 │ nothing │ record │ + ╰───┴─────────┴────────╯ Examples: - Set the volume of Spotify to 50% - > dbus set --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player Volume 0.5 + Look at the MPRIS2 interfaces exposed by Spotify + > dbus introspect --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 | explore -## `dbus list` + Get methods exposed by KDE Plasma's on-screen display service + > dbus introspect --dest=org.kde.plasmashell /org/kde/osdService | get interfaces | where name == org.kde.osdService | get 0.methods + + List objects exposed by KWin + > dbus introspect --dest=org.kde.KWin / | get children | select name + +# `dbus list` List all available connection names on the bus @@ -220,6 +230,13 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi Parameters: pattern : An optional glob-like pattern to filter the result by (optional) + Input/output types: + ╭───┬─────────┬──────────────╮ + │ # │ input │ output │ + ├───┼─────────┼──────────────┤ + │ 0 │ nothing │ list │ + ╰───┴─────────┴──────────────╯ + Examples: List all names available on the bus > dbus list @@ -238,3 +255,43 @@ Then add `register ~/.cargo/bin/nu_plugin_dbus` to your `~/.config/nushell/confi │ 0 │ org.mpris.MediaPlayer2.spotify │ │ 1 │ org.mpris.MediaPlayer2.kdeconnect.mpris_000001 │ ╰───┴────────────────────────────────────────────────╯ + +# `dbus set` + + Set a D-Bus property + + Search terms: dbus + + Usage: + > dbus set {flags} + + Flags: + -h, --help - Display the help message for this command + --session - Send to the session message bus (default) + --system - Send to the system message bus + --started - Send to the bus that started this process, if applicable + --bus - Send to the bus server at the given address + --peer - Send to a non-bus D-Bus server at the given address. Will not call the Hello method on initialization. + --timeout - How long to wait for a response + --signature - Signature of the value to set, in D-Bus format. + If not provided, it will be determined from introspection. + If --no-introspect is specified and this is not provided, it will be guessed (poorly) + --dest (required parameter) - The name of the connection to write the property on + + Parameters: + object : The path to the object to write the property on + interface : The name of the interface the property belongs to + property : The name of the property to write + value : The value to write to the property + + Input/output types: + ╭───┬─────────┬─────────╮ + │ # │ input │ output │ + ├───┼─────────┼─────────┤ + │ 0 │ nothing │ nothing │ + ╰───┴─────────┴─────────╯ + + Examples: + Set the volume of Spotify to 50% + > dbus set --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player Volume 0.5 + diff --git a/src/main.rs b/src/main.rs index ca055bd..4e2183b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin, EvaluatedCall, LabeledError}; -use nu_protocol::{PluginSignature, Value, SyntaxShape, PluginExample, Span}; +use nu_protocol::{PluginSignature, Value, SyntaxShape, PluginExample, Span, Type}; mod config; mod client; @@ -34,6 +34,7 @@ impl Plugin for NuPluginDbus { .accepts_dbus_client_options() .accepts_timeout() .usage("Introspect a D-Bus object") + .input_output_type(Type::Nothing, Type::Record(vec![])) .extra_usage("Returns information about available nodes, interfaces, methods, \ signals, and properties on the given object path") .required_named("dest", SyntaxShape::String, @@ -69,6 +70,7 @@ impl Plugin for NuPluginDbus { .accepts_timeout() .usage("Call a method and get its response") .extra_usage("Returns an array if the method call returns more than one value.") + .input_output_type(Type::Nothing, Type::Any) .named("signature", SyntaxShape::String, "Signature of the arguments to send, in D-Bus format.\n \ If not provided, they will be determined from introspection.\n \ @@ -110,6 +112,7 @@ impl Plugin for NuPluginDbus { .accepts_dbus_client_options() .accepts_timeout() .usage("Get a D-Bus property") + .input_output_type(Type::Nothing, Type::Any) .required_named("dest", SyntaxShape::String, "The name of the connection to read the property from", None) @@ -139,7 +142,8 @@ impl Plugin for NuPluginDbus { .is_dbus_command() .accepts_dbus_client_options() .accepts_timeout() - .usage("Get all D-Bus property for the given objects") + .usage("Get all D-Bus properties for the given object") + .input_output_type(Type::Nothing, Type::Record(vec![])) .required_named("dest", SyntaxShape::String, "The name of the connection to read the property from", None) @@ -164,7 +168,8 @@ impl Plugin for NuPluginDbus { .is_dbus_command() .accepts_dbus_client_options() .accepts_timeout() - .usage("Get all D-Bus property for the given objects") + .usage("Set a D-Bus property") + .input_output_type(Type::Nothing, Type::Nothing) .named("signature", SyntaxShape::String, "Signature of the value to set, in D-Bus format.\n \ If not provided, it will be determined from introspection.\n \ @@ -196,6 +201,7 @@ impl Plugin for NuPluginDbus { .accepts_timeout() .usage("List all available connection names on the bus") .extra_usage("These can be used as arguments for --dest on any of the other commands.") + .input_output_type(Type::Nothing, Type::List(Type::String.into())) .optional("pattern", SyntaxShape::String, "An optional glob-like pattern to filter the result by") .plugin_examples(vec![