forked from extern/nushell
Support URLs in start
command (#7799)
# Description Fixes issue #7792 Fix basically by @kubouch , "stolen" by me :). Edit: Added "proper" fix rather than the one liner ``` start Cargo.toml // Opens in default editor ``` ``` start https://www.google.com [alternative_browser] // Opens page in default browser or another browser if specified ``` # User-Facing Changes _(List of all changes that impact the user experience here. This helps us keep track of breaking changes.)_ # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [X] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [X] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - [X] `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
parent
30ac2d220c
commit
1fd1a3a456
@ -1,8 +1,9 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@ -15,7 +16,7 @@ impl Command for Start {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Open a folder or file in the default application or viewer."
|
||||
"Open a folder,file or website in the default application or viewer."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
@ -25,7 +26,7 @@ impl Command for Start {
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("start")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Any), (Type::String, Type::Any)])
|
||||
.optional("filepath", SyntaxShape::Filepath, "the filepath to open")
|
||||
.required("path", SyntaxShape::String, "path to open")
|
||||
.category(Category::FileSystem)
|
||||
}
|
||||
|
||||
@ -34,45 +35,68 @@ impl Command for Start {
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let path = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
|
||||
|
||||
let path = {
|
||||
if let Some(path_val) = path {
|
||||
Some(Spanned {
|
||||
item: nu_utils::strip_ansi_string_unlikely(path_val.item),
|
||||
span: path_val.span,
|
||||
})
|
||||
} else {
|
||||
path
|
||||
}
|
||||
};
|
||||
|
||||
let path = if let Some(path) = path {
|
||||
path
|
||||
} else {
|
||||
// Collect a filename from the input
|
||||
match input {
|
||||
PipelineData::Value(Value::Nothing { .. }, ..) => {
|
||||
return Err(ShellError::MissingParameter(
|
||||
"needs filename".to_string(),
|
||||
call.head,
|
||||
))
|
||||
}
|
||||
PipelineData::Value(val, ..) => val.as_spanned_string()?,
|
||||
_ => {
|
||||
return Err(ShellError::MissingParameter(
|
||||
"needs filename".to_string(),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
}
|
||||
let path = call.req::<Spanned<String>>(engine_state, stack, 0)?;
|
||||
let path = Spanned {
|
||||
item: nu_utils::strip_ansi_string_unlikely(path.item),
|
||||
span: path.span,
|
||||
};
|
||||
let path_no_whitespace = &path.item.trim_end_matches(|x| matches!(x, '\x09'..='\x0d'));
|
||||
let path = Path::new(path_no_whitespace);
|
||||
|
||||
open::that(path)?;
|
||||
// only check if file exists in current current directory
|
||||
let file_path = Path::new(path_no_whitespace);
|
||||
if file_path.exists() {
|
||||
open::that(path_no_whitespace)?;
|
||||
} else if file_path.starts_with("https://") || file_path.starts_with("http://") {
|
||||
let url = url::Url::parse(&path.item).map_err(|_| {
|
||||
ShellError::GenericError(
|
||||
format!("Cannot parse url: {}", &path.item),
|
||||
"".to_string(),
|
||||
Some(path.span),
|
||||
Some("cannot parse".to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
open::that(url.as_str())?;
|
||||
} else {
|
||||
// try to distinguish between file not found and opening url without prefix
|
||||
if let Ok(path) =
|
||||
canonicalize_with(path_no_whitespace, std::env::current_dir()?.as_path())
|
||||
{
|
||||
open::that(path)?;
|
||||
} else {
|
||||
// open crate does not allow opening URL without prefix
|
||||
let path_with_prefix = Path::new("https://").join(&path.item);
|
||||
let common_domains = vec!["com", "net", "org", "edu", "sh"];
|
||||
if let Some(url) = path_with_prefix.to_str() {
|
||||
let url = url::Url::parse(url).map_err(|_| {
|
||||
ShellError::GenericError(
|
||||
format!("Cannot parse url: {}", &path.item),
|
||||
"".to_string(),
|
||||
Some(path.span),
|
||||
Some("cannot parse".to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
if let Some(domain) = url.host() {
|
||||
let domain = domain.to_string();
|
||||
let ext = Path::new(&domain).extension().and_then(|s| s.to_str());
|
||||
if let Some(url_ext) = ext {
|
||||
if common_domains.contains(&url_ext) {
|
||||
open::that(url.as_str())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(ShellError::GenericError(
|
||||
format!("Cannot find file or url: {}", &path.item),
|
||||
"".to_string(),
|
||||
Some(path.span),
|
||||
Some("Use prefix https:// to disambiguate URLs from files".to_string()),
|
||||
Vec::new(),
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(PipelineData::Empty)
|
||||
}
|
||||
|
||||
@ -98,6 +122,11 @@ impl Command for Start {
|
||||
example: "start file.pdf",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Open a website with default browser",
|
||||
example: "start https://www.nushell.sh",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user