diff --git a/Cargo.lock b/Cargo.lock
index 180b4bd..5f2e3a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1357,9 +1357,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.110"
+version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b58a4469763e4e3a906c4ed786e1c70512d16aa88f84dded826da42640fc6a1c"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "libdbus-sys"
@@ -1731,6 +1731,7 @@ dependencies = [
"futures 0.3.18",
"ioctl-rs",
"lazy_static 1.4.0",
+ "libc",
"librespot-core",
"librespot-playback",
"librespot-protocol",
diff --git a/Cargo.toml b/Cargo.toml
index 5fcfb65..2b1fd82 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -46,6 +46,7 @@ regex = "1"
ioctl-rs = { version = "0.2", optional = true }
serde_cbor = "0.11.2"
pancurses = { version = "0.17.0", features = ["win32"] }
+libc = "0.2.111"
[dependencies.rspotify]
version = "0.11.3"
diff --git a/README.md b/README.md
index 7d28e30..679e9b6 100644
--- a/README.md
+++ b/README.md
@@ -259,18 +259,19 @@ time with Escape.
The following commands are supported:
-| Command | Action |
-| :--------------------------------- | :--------------------------------------------------------------- |
-| `quit` | Quit `ncspot`. |
-| `logout` | Remove any cached credentials from disk and quit `ncspot`. |
-| `toggle` | Toggle playback. |
-| `stop` | Stop playback. |
-| `previous` | Play previous track. |
-| `next` | Play next track. |
-| `clear` | Clear playlist. |
-| `share - ` | Copies a sharable URL of the item to the system clipboard. |
-| `newplaylist ` | Create new playlist with name ``. |
+| Command | Action |
+|---|---|
+| `quit` | Quit `ncspot`. |
+| `logout` | Remove any cached credentials from disk and quit `ncspot`. |
+| `toggle` | Toggle playback. |
+| `stop` | Stop playback. |
+| `previous` | Play previous track. |
+| `next` | Play next track. |
+| `clear` | Clear playlist. |
+| `share
- ` | Copies a sharable URL of the item to the system clipboard. |
+| `newplaylist ` | Create new playlist with name ``. |
| `sort ` | Sort a playlist by `` in direction ``. |
+| `exec ` | Executes a command in the system shell. Be aware that command output is printed to the terminal, so redirection to `/dev/null` e.g. by appending `2> /dev/null` may be necessary. |
Supported `
- ` are:
diff --git a/src/command.rs b/src/command.rs
index 7d70a5d..1ba021a 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -136,6 +136,7 @@ pub enum Command {
Logout,
ShowRecommendations(TargetMode),
Redraw,
+ Execute(String),
}
impl fmt::Display for Command {
@@ -191,7 +192,7 @@ impl fmt::Display for Command {
Command::Jump(mode) => match mode {
JumpMode::Previous => "jumpprevious".to_string(),
JumpMode::Next => "jumpnext".to_string(),
- JumpMode::Query(term) => format!("jump {}", term).to_string(),
+ JumpMode::Query(term) => String::from(format!("jump {}", term)),
},
Command::Help => "help".to_string(),
Command::ReloadConfig => "reload".to_string(),
@@ -201,6 +202,7 @@ impl fmt::Display for Command {
Command::Logout => "logout".to_string(),
Command::ShowRecommendations(mode) => format!("similar {}", mode),
Command::Redraw => "redraw".to_string(),
+ Command::Execute(cmd) => format!("exec {}", cmd),
};
// escape the command separator
let repr = repr.replace(";", ";;");
@@ -471,6 +473,7 @@ pub fn parse(input: &str) -> Option> {
.map(Command::ShowRecommendations),
"noop" => Some(Command::Noop),
"redraw" => Some(Command::Redraw),
+ "exec" => Some(Command::Execute(args.join(" "))),
_ => None,
};
commands.push(command?);
diff --git a/src/commands.rs b/src/commands.rs
index 0520451..4997700 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -253,6 +253,13 @@ impl CommandManager {
s.quit();
Ok(None)
}
+ Command::Execute(cmd) => {
+ log::info!("Executing command: {}", cmd);
+ let cmd = std::ffi::CString::new(cmd.clone()).unwrap();
+ let result = unsafe { libc::system(cmd.as_ptr()) };
+ log::info!("Exit code: {}", result);
+ Ok(None)
+ }
Command::Jump(_)
| Command::Move(_, _)
| Command::Shift(_, _)