Move old plugins (#4721)

This commit is contained in:
JT
2022-03-04 09:36:03 -05:00
committed by GitHub
parent 89b7f4d57c
commit eef3de2d05
61 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,26 @@
[package]
authors = ["The Nu Project Contributors"]
description = "A plugin to open files/URLs directly from Nushell"
edition = "2018"
license = "MIT"
name = "nu_plugin_start"
version = "0.59.1"
[lib]
doctest = false
[dependencies]
glob = "0.3.0"
nu-errors = { path="../nu-errors", version = "0.59.1" }
nu-plugin = { path="../nu-plugin", version = "0.59.1" }
nu-protocol = { path="../nu-protocol", version = "0.59.1" }
nu-source = { path="../nu-source", version = "0.59.1" }
url = "2.2.0"
webbrowser = "0.5.5"
[target.'cfg(windows)'.dependencies]
open = "1.4.0"
[build-dependencies]
nu-errors = { version = "0.59.1", path="../nu-errors" }
nu-source = { version = "0.59.1", path="../nu-source" }

View File

@ -0,0 +1,4 @@
mod nu;
mod start;
pub use start::Start;

View File

@ -0,0 +1,6 @@
use nu_plugin::serve_plugin;
use nu_plugin_start::Start;
fn main() {
serve_plugin(&mut Start::new());
}

View File

@ -0,0 +1,28 @@
use nu_errors::ShellError;
use nu_plugin::Plugin;
use nu_protocol::{CallInfo, ReturnValue, Signature, SyntaxShape};
use crate::start::Start;
impl Plugin for Start {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("start")
.desc("Opens each file/directory/URL using the default application")
.rest(
"rest",
SyntaxShape::String,
"files/urls/directories to open",
)
.named(
"application",
SyntaxShape::String,
"Specifies the application used for opening the files/directories/urls",
Some('a'),
)
.filter())
}
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
self.parse(call_info)?;
self.exec().map(|_| Vec::new())
}
}

View File

@ -0,0 +1,260 @@
use nu_errors::ShellError;
use nu_protocol::{CallInfo, Value};
use nu_source::{Tag, Tagged, TaggedItem};
use std::path::Path;
#[cfg(not(target_os = "windows"))]
use std::process::{Command, Stdio};
#[derive(Default)]
pub struct Start {
pub tag: Tag,
pub filenames: Vec<Tagged<String>>,
pub application: Option<String>,
}
impl Start {
pub fn new() -> Start {
Start {
tag: Tag::unknown(),
filenames: vec![],
application: None,
}
}
pub fn parse(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
self.tag = call_info.name_tag.clone();
self.parse_input_parameters(&call_info)?;
self.parse_application(&call_info);
Ok(())
}
fn add_filename(&mut self, filename: Tagged<String>) -> Result<(), ShellError> {
if Path::new(&filename.item).exists() || url::Url::parse(&filename.item).is_ok() {
self.filenames.push(filename);
Ok(())
} else {
Err(ShellError::labeled_error(
format!("The file '{}' does not exist", filename.item),
"doesn't exist",
filename.tag,
))
}
}
fn glob_to_values(&self, value: &Value) -> Result<Vec<Tagged<String>>, ShellError> {
let mut result = vec![];
match glob::glob(&value.as_string()?) {
Ok(paths) => {
for path_result in paths {
match path_result {
Ok(path) => result
.push(path.to_string_lossy().to_string().tagged(value.tag.clone())),
Err(glob_error) => {
return Err(ShellError::labeled_error(
glob_error.to_string(),
"glob error",
value.tag.clone(),
));
}
}
}
}
Err(pattern_error) => {
return Err(ShellError::labeled_error(
pattern_error.to_string(),
"invalid pattern",
value.tag.clone(),
))
}
}
Ok(result)
}
fn parse_input_parameters(&mut self, call_info: &CallInfo) -> Result<(), ShellError> {
let candidates = match &call_info.args.positional {
Some(values) => {
let mut result = vec![];
for value in values {
let val_str = value.as_string();
match val_str {
Ok(s) => {
if s.to_ascii_lowercase().starts_with("http")
|| s.to_ascii_lowercase().starts_with("https")
{
if webbrowser::open(&s).is_ok() {
result.push("http/web".to_string().tagged_unknown())
} else {
return Err(ShellError::labeled_error(
&format!("error opening {}", &s),
"error opening url",
self.tag.span,
));
}
} else {
let res = self.glob_to_values(value)?;
result.extend(res);
}
}
Err(e) => {
return Err(ShellError::labeled_error(
e.to_string(),
"no input given",
self.tag.span,
));
}
}
}
if result.is_empty() {
return Err(ShellError::labeled_error(
"No input given",
"no input given",
self.tag.span,
));
}
result
}
None => {
return Err(ShellError::labeled_error(
"No input given",
"no input given",
self.tag.span,
))
}
};
for candidate in candidates {
if !candidate.contains("http/web") {
self.add_filename(candidate)?;
}
}
Ok(())
}
fn parse_application(&mut self, call_info: &CallInfo) {
self.application = if let Some(app) = call_info.args.get("application") {
match app.as_string() {
Ok(name) => Some(name),
Err(_) => None,
}
} else {
None
};
}
#[cfg(target_os = "macos")]
pub fn exec(&mut self) -> Result<(), ShellError> {
let mut args = vec![];
args.append(
&mut self
.filenames
.iter()
.map(|x| x.item.clone())
.collect::<Vec<_>>(),
);
if let Some(app_name) = &self.application {
args.append(&mut vec![String::from("-a"), app_name.to_string()]);
}
exec_cmd("open", &args, self.tag.clone())
}
#[cfg(target_os = "windows")]
pub fn exec(&mut self) -> Result<(), ShellError> {
if let Some(app_name) = &self.application {
for file in &self.filenames {
match open::with(&file.item, app_name) {
Ok(_) => continue,
Err(_) => {
return Err(ShellError::labeled_error(
"Failed to open file with specified application",
"can't open with specified application",
file.tag.span,
))
}
}
}
} else {
for file in &self.filenames {
match open::that(&file.item) {
Ok(_) => continue,
Err(_) => {
return Err(ShellError::labeled_error(
"Failed to open file with default application",
"can't open with default application",
file.tag.span,
))
}
}
}
}
Ok(())
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn exec(&mut self) -> Result<(), ShellError> {
let mut args = vec![];
args.append(
&mut self
.filenames
.iter()
.map(|x| x.item.clone())
.collect::<Vec<_>>(),
);
if let Some(app_name) = &self.application {
exec_cmd(app_name, &args, self.tag.clone())
} else {
for cmd in ["xdg-open", "gnome-open", "kde-open", "wslview"] {
if exec_cmd(cmd, &args, self.tag.clone()).is_err() {
continue;
} else {
return Ok(());
}
}
Err(ShellError::labeled_error(
"Failed to open file(s) with xdg-open. gnome-open, kde-open, and wslview",
"failed to open xdg-open. gnome-open, kde-open, and wslview",
self.tag.span,
))
}
}
}
#[cfg(not(target_os = "windows"))]
fn exec_cmd(cmd: &str, args: &[String], tag: Tag) -> Result<(), ShellError> {
if args.is_empty() {
return Err(ShellError::labeled_error(
"No file(s) or application provided",
"no file(s) or application provided",
tag,
));
}
let status = match Command::new(cmd)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(args)
.status()
{
Ok(exit_code) => exit_code,
Err(_) => {
return Err(ShellError::labeled_error(
"Failed to run native open syscall",
"failed to run native open call",
tag,
))
}
};
if status.success() {
Ok(())
} else {
Err(ShellError::labeled_error(
"Failed to run start. Hint: The file(s)/application may not exist",
"failed to run",
tag,
))
}
}