feat(api/shell): allow open command to open files (#1341)

This commit is contained in:
Noah Klayman 2021-03-09 20:20:54 -08:00 committed by GitHub
parent e996e1bcbd
commit 7c0bf642a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 54 deletions

View File

@ -7,7 +7,7 @@ import { invokeTauriCommand } from './helpers/tauri'
* @param [args] command args
* @return promise resolving to the stdout text
*/
async function execute(
async function execute (
command: string,
args?: string | string[]
): Promise<string> {
@ -26,16 +26,19 @@ async function execute(
}
/**
* opens an URL on the user default browser
* opens a path or URL with the system's default app,
* or the one specified with `openWith`
*
* @param url the URL to open
* @param path the path or URL to open
* @param openWith the app to open the file or URL with
*/
async function open(url: string): Promise<void> {
async function open (path: string, openWith?: string): Promise<void> {
return invokeTauriCommand({
__tauriModule: 'Shell',
message: {
cmd: 'open',
uri: url
path,
with: openWith
}
})
}

View File

@ -37,6 +37,7 @@ clap = { version = "=3.0.0-beta.2", optional = true }
notify-rust = { version = "4.3.0", optional = true }
once_cell = "1.7.2"
tauri-hotkey = { git = "https://github.com/tauri-apps/tauri-hotkey-rs", branch = "dev", optional = true }
open = "1.5.1"
[dev-dependencies]
quickcheck = "1.0.3"

View File

@ -61,4 +61,7 @@ pub enum Error {
#[cfg(feature = "global-shortcut")]
#[error("shortcut error: {0}")]
Shortcut(#[from] tauri_hotkey::Error),
/// Shell error.
#[error("shell error: {0}")]
Shell(String),
}

View File

@ -15,6 +15,8 @@ pub mod http;
pub mod path;
/// The RPC module includes utilities to send messages to the JS layer of the webview.
pub mod rpc;
/// The shell api.
pub mod shell;
/// TCP ports access API.
pub mod tcp;
/// The semver API.

23
tauri-api/src/shell.rs Normal file
View File

@ -0,0 +1,23 @@
/// Open path or URL with `with`, or system default
pub fn open(path: String, with: Option<String>) -> crate::Result<()> {
{
let exit_status = if let Some(with) = with {
open::with(&path, &with)
} else {
open::that(&path)
};
match exit_status {
Ok(status) => {
if status.success() {
Ok(())
} else {
Err(crate::Error::Shell("open command failed".into()))
}
}
Err(err) => Err(crate::Error::Shell(format!(
"failed to open: {}",
err.to_string()
))),
}
}
}

View File

@ -21,7 +21,6 @@ features = [ "api-all" ]
serde_json = "1.0"
serde = { version = "1.0", features = [ "derive" ] }
base64 = "0.13.0"
webbrowser = "0.5.5"
lazy_static = "1.4.0"
tokio = { version = "1.2", features = ["rt", "rt-multi-thread", "sync"] }
futures = "0.3"

View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.4"
@ -1855,9 +1857,19 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.7.0"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "open"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2033f93630dd4b04768ecf5e16bcd3002a89e1e1dbef375bf290dd67e2b7a4d"
dependencies = [
"which",
"winapi 0.3.9",
]
[[package]]
name = "openssl"
@ -2766,7 +2778,6 @@ dependencies = [
"thiserror",
"tokio",
"uuid",
"webbrowser",
"wry",
]
@ -2782,6 +2793,7 @@ dependencies = [
"http",
"notify-rust",
"once_cell",
"open",
"rand 0.8.3",
"reqwest",
"rfd",
@ -3337,17 +3349,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webbrowser"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a"
dependencies = [
"web-sys",
"widestring",
"winapi 0.3.9",
]
[[package]]
name = "webkit2gtk"
version = "0.11.0"
@ -3430,6 +3431,16 @@ dependencies = [
"cc",
]
[[package]]
name = "which"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef"
dependencies = [
"libc",
"thiserror",
]
[[package]]
name = "widestring"
version = "0.4.3"

View File

@ -26,7 +26,9 @@
setIcon
} = appWindow
let urlValue = "https://tauri.studio";
export let onMessage;
let pathValue = "https://tauri.studio";
let openWith = "";
let resizable = true
let maximized = false
let decorations = false
@ -44,7 +46,7 @@
let windowTitle = 'Awesome Tauri Example!';
function openUrl() {
open(urlValue);
open(pathValue, !!openWith ? openWith : undefined).catch(onMessage);
}
function setTitle_() {
@ -188,8 +190,15 @@
<button class="button" type="submit">Set title</button>
</form>
<form style="margin-top: 24px" on:submit|preventDefault={openUrl}>
<input id="url" bind:value={urlValue} />
<button class="button" id="open-url">
Open URL
<div>
<label for="path">Path or URL:</label>
<input id="path" bind:value={pathValue} />
</div>
<div>
<label for="openWith">Open With (Optional):</label>
<input id="openWith" bind:value={openWith} />
</div>
<button class="button" id="open-path">
Open Path or Url
</button>
</form>

View File

@ -6,9 +6,14 @@ use serde::Deserialize;
#[serde(tag = "cmd", rename_all = "camelCase")]
pub enum Cmd {
/// The execute script API.
Execute { command: String, args: Vec<String> },
/// The open URL in browser API
Open { uri: String },
Execute {
command: String,
args: Vec<String>,
},
Open {
path: String,
with: Option<String>,
},
}
impl Cmd {
@ -28,37 +33,16 @@ impl Cmd {
"shell > execute".to_string(),
))
}
Self::Open { uri } => {
Self::Open { path, with } => {
#[cfg(shell_open)]
{
open_browser(uri);
Ok(().into())
match crate::api::shell::open(path, with) {
Ok(_) => Ok(().into()),
Err(err) => Err(crate::Error::FailedToExecuteApi(err)),
}
#[cfg(not(shell_open))]
Err(crate::Error::ApiNotAllowlisted("shell > open".to_string()))
}
}
}
}
#[cfg(shell_open)]
pub fn open_browser(uri: String) {
#[cfg(test)]
assert!(uri.contains("http://"));
#[cfg(not(test))]
webbrowser::open(&uri).expect("Failed to open webbrowser with uri");
}
#[cfg(test)]
mod test {
use proptest::prelude::*;
// Test the open func to see if proper uris can be opened by the browser.
proptest! {
#[cfg(shell_open)]
#[test]
fn check_open(uri in r"(http://)([\\w\\d\\.]+([\\w]{2,6})?)") {
super::open_browser(uri);
}
}
}