mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 10:48:37 +02:00
Merge master
This commit is contained in:
@ -3,7 +3,6 @@ use crate::commands::cp::CopyArgs;
|
||||
use crate::commands::mkdir::MkdirArgs;
|
||||
use crate::commands::mv::MoveArgs;
|
||||
use crate::commands::rm::RemoveArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::data::dir_entry_dict;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::NuCompleter;
|
||||
@ -12,6 +11,8 @@ use crate::utils::FileStructure;
|
||||
use rustyline::completion::FilenameCompleter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::Ordering;
|
||||
use trash as SendToTrash;
|
||||
|
||||
pub struct FilesystemShell {
|
||||
pub(crate) path: String,
|
||||
@ -73,7 +74,7 @@ impl FilesystemShell {
|
||||
}
|
||||
|
||||
impl Shell for FilesystemShell {
|
||||
fn name(&self, _source_map: &SourceMap) -> String {
|
||||
fn name(&self) -> String {
|
||||
"filesystem".to_string()
|
||||
}
|
||||
|
||||
@ -84,7 +85,7 @@ impl Shell for FilesystemShell {
|
||||
fn ls(
|
||||
&self,
|
||||
pattern: Option<Tagged<PathBuf>>,
|
||||
command_tag: Tag,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let cwd = self.path();
|
||||
let mut full_path = PathBuf::from(self.path());
|
||||
@ -94,7 +95,8 @@ impl Shell for FilesystemShell {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut shell_entries = VecDeque::new();
|
||||
let ctrl_c = context.ctrl_c.clone();
|
||||
let name_tag = context.name.clone();
|
||||
|
||||
//If it's not a glob, try to display the contents of the entry if it's a directory
|
||||
let lossy_path = full_path.to_string_lossy();
|
||||
@ -114,24 +116,33 @@ impl Shell for FilesystemShell {
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
command_tag,
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
for entry in entries {
|
||||
let entry = entry?;
|
||||
let filepath = entry.path();
|
||||
let filename = if let Ok(fname) = filepath.strip_prefix(&cwd) {
|
||||
fname
|
||||
} else {
|
||||
Path::new(&filepath)
|
||||
};
|
||||
let value = dir_entry_dict(filename, &entry.metadata()?, command_tag)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
return Ok(shell_entries.to_output_stream());
|
||||
let stream = async_stream! {
|
||||
for entry in entries {
|
||||
if ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
if let Ok(entry) = entry {
|
||||
let filepath = entry.path();
|
||||
if let Ok(metadata) = std::fs::symlink_metadata(&filepath) {
|
||||
let filename = if let Ok(fname) = filepath.strip_prefix(&cwd) {
|
||||
fname
|
||||
} else {
|
||||
Path::new(&filepath)
|
||||
};
|
||||
|
||||
let value = dir_entry_dict(filename, &metadata, &name_tag)?;
|
||||
yield ReturnSuccess::value(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return Ok(stream.to_output_stream());
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,26 +156,33 @@ impl Shell for FilesystemShell {
|
||||
source.tag(),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("Invalid pattern."));
|
||||
return Err(ShellError::untagged_runtime_error("Invalid pattern."));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Enumerate the entries from the glob and add each
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
let filename = if let Ok(fname) = entry.strip_prefix(&cwd) {
|
||||
fname
|
||||
} else {
|
||||
Path::new(&entry)
|
||||
};
|
||||
let metadata = std::fs::metadata(&entry)?;
|
||||
let value = dir_entry_dict(filename, &metadata, command_tag)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
}
|
||||
let stream = async_stream! {
|
||||
for entry in entries {
|
||||
if ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
if let Ok(entry) = entry {
|
||||
if let Ok(metadata) = std::fs::symlink_metadata(&entry) {
|
||||
let filename = if let Ok(fname) = entry.strip_prefix(&cwd) {
|
||||
fname
|
||||
} else {
|
||||
Path::new(&entry)
|
||||
};
|
||||
|
||||
Ok(shell_entries.to_output_stream())
|
||||
if let Ok(value) = dir_entry_dict(filename, &metadata, &name_tag) {
|
||||
yield ReturnSuccess::value(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
@ -175,7 +193,7 @@ impl Shell for FilesystemShell {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
args.call_info.name_tag,
|
||||
&args.call_info.name_tag,
|
||||
))
|
||||
}
|
||||
},
|
||||
@ -605,26 +623,71 @@ impl Shell for FilesystemShell {
|
||||
}
|
||||
|
||||
if entry.is_file() {
|
||||
match std::fs::rename(&entry, &destination) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
match std::fs::rename(&entry, &destination) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
match std::fs::copy(&entry, &destination) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(_) => match std::fs::remove_file(&entry) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if entry.is_dir() {
|
||||
@ -727,26 +790,45 @@ impl Shell for FilesystemShell {
|
||||
}
|
||||
|
||||
if src.is_file() {
|
||||
match std::fs::rename(src, dst) {
|
||||
match std::fs::copy(&src, &dst) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
src,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
src,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
}
|
||||
Ok(_) => match std::fs::remove_file(&src) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -806,26 +888,71 @@ impl Shell for FilesystemShell {
|
||||
to.push(entry_file_name);
|
||||
|
||||
if entry.is_file() {
|
||||
match std::fs::rename(&entry, &to) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
match std::fs::rename(&entry, &to) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
match std::fs::copy(&entry, &to) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Rename {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(_) => match std::fs::remove_file(&entry) {
|
||||
Err(e) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
format!(
|
||||
"Remove {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
format!(
|
||||
"Remove {:?} to {:?} aborted. {:}",
|
||||
entry_file_name,
|
||||
destination_file_name,
|
||||
e.to_string(),
|
||||
),
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -843,7 +970,11 @@ impl Shell for FilesystemShell {
|
||||
|
||||
fn rm(
|
||||
&self,
|
||||
RemoveArgs { target, recursive }: RemoveArgs,
|
||||
RemoveArgs {
|
||||
target,
|
||||
recursive,
|
||||
trash,
|
||||
}: RemoveArgs,
|
||||
name: Tag,
|
||||
path: &str,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
@ -926,7 +1057,9 @@ impl Shell for FilesystemShell {
|
||||
));
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
if trash.item {
|
||||
SendToTrash::remove(path).unwrap();
|
||||
} else if path.is_dir() {
|
||||
std::fs::remove_dir_all(&path)?;
|
||||
} else if path.is_file() {
|
||||
std::fs::remove_file(&path)?;
|
||||
@ -957,7 +1090,7 @@ impl Shell for FilesystemShell {
|
||||
return Err(ShellError::labeled_error(
|
||||
"unable to show current directory",
|
||||
"pwd command failed",
|
||||
args.call_info.name_tag,
|
||||
&args.call_info.name_tag,
|
||||
));
|
||||
}
|
||||
};
|
||||
@ -965,7 +1098,7 @@ impl Shell for FilesystemShell {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(p.to_string_lossy().to_string()))
|
||||
.tagged(args.call_info.name_tag),
|
||||
.tagged(&args.call_info.name_tag),
|
||||
));
|
||||
|
||||
Ok(stream.into())
|
||||
|
@ -3,7 +3,6 @@ use crate::commands::cp::CopyArgs;
|
||||
use crate::commands::mkdir::MkdirArgs;
|
||||
use crate::commands::mv::MoveArgs;
|
||||
use crate::commands::rm::RemoveArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::data::{command_dict, TaggedDictBuilder};
|
||||
use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
@ -98,8 +97,8 @@ impl HelpShell {
|
||||
}
|
||||
|
||||
impl Shell for HelpShell {
|
||||
fn name(&self, source_map: &SourceMap) -> String {
|
||||
let anchor_name = self.value.anchor_name(source_map);
|
||||
fn name(&self) -> String {
|
||||
let anchor_name = self.value.anchor_name();
|
||||
format!(
|
||||
"{}",
|
||||
match anchor_name {
|
||||
@ -129,7 +128,7 @@ impl Shell for HelpShell {
|
||||
fn ls(
|
||||
&self,
|
||||
_pattern: Option<Tagged<PathBuf>>,
|
||||
_command_tag: Tag,
|
||||
_context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(self
|
||||
.commands()
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::context::Context;
|
||||
use crate::parser::hir::syntax_shape::{color_fallible_syntax, FlatShape, PipelineShape};
|
||||
use crate::parser::hir::TokensIterator;
|
||||
use crate::parser::nom_input;
|
||||
use crate::parser::parse::token_tree::TokenNode;
|
||||
use crate::parser::parse::tokens::RawToken;
|
||||
use crate::parser::{Pipeline, PipelineElement};
|
||||
use crate::shell::shell_manager::ShellManager;
|
||||
use crate::Tagged;
|
||||
use crate::{HasSpan, Spanned, SpannedItem, Tag, Tagged, Text};
|
||||
use ansi_term::Color;
|
||||
use log::{log_enabled, trace};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::Highlighter;
|
||||
@ -12,12 +13,12 @@ use rustyline::hint::Hinter;
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
pub(crate) struct Helper {
|
||||
helper: ShellManager,
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl Helper {
|
||||
pub(crate) fn new(helper: ShellManager) -> Helper {
|
||||
Helper { helper }
|
||||
pub(crate) fn new(context: Context) -> Helper {
|
||||
Helper { context }
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,30 +30,13 @@ impl Completer for Helper {
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
self.helper.complete(line, pos, ctx)
|
||||
self.context.shell_manager.complete(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Completer for Helper {
|
||||
type Candidate = rustyline::completion::Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
let result = self.helper.complete(line, pos, ctx);
|
||||
|
||||
result.map(|(x, y)| (x, y.iter().map(|z| z.into()).collect()))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Hinter for Helper {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.helper.hint(line, pos, ctx)
|
||||
self.context.shell_manager.hint(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +50,7 @@ impl Highlighter for Helper {
|
||||
}
|
||||
|
||||
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
|
||||
let tokens = crate::parser::pipeline(nom_input(line, uuid::Uuid::nil()));
|
||||
let tokens = crate::parser::pipeline(nom_input(line));
|
||||
|
||||
match tokens {
|
||||
Err(_) => Cow::Borrowed(line),
|
||||
@ -77,24 +61,49 @@ impl Highlighter for Helper {
|
||||
Ok(v) => v,
|
||||
};
|
||||
|
||||
let Pipeline { parts, post_ws } = pipeline;
|
||||
let mut iter = parts.into_iter();
|
||||
let tokens = vec![TokenNode::Pipeline(pipeline.clone().spanned(v.span()))];
|
||||
let mut tokens = TokensIterator::all(&tokens[..], v.span());
|
||||
|
||||
loop {
|
||||
match iter.next() {
|
||||
None => {
|
||||
if let Some(ws) = post_ws {
|
||||
out.push_str(ws.slice(line));
|
||||
}
|
||||
let text = Text::from(line);
|
||||
let expand_context = self.context.expand_context(&text);
|
||||
|
||||
return Cow::Owned(out);
|
||||
}
|
||||
Some(token) => {
|
||||
let styled = paint_pipeline_element(&token, line);
|
||||
out.push_str(&styled.to_string());
|
||||
}
|
||||
}
|
||||
#[cfg(not(coloring_in_tokens))]
|
||||
let shapes = {
|
||||
let mut shapes = vec![];
|
||||
color_fallible_syntax(
|
||||
&PipelineShape,
|
||||
&mut tokens,
|
||||
&expand_context,
|
||||
&mut shapes,
|
||||
)
|
||||
.unwrap();
|
||||
shapes
|
||||
};
|
||||
|
||||
#[cfg(coloring_in_tokens)]
|
||||
let shapes = {
|
||||
// We just constructed a token list that only contains a pipeline, so it can't fail
|
||||
color_fallible_syntax(&PipelineShape, &mut tokens, &expand_context).unwrap();
|
||||
tokens.with_color_tracer(|_, tracer| tracer.finish());
|
||||
|
||||
tokens.state().shapes()
|
||||
};
|
||||
|
||||
trace!(target: "nu::color_syntax", "{:#?}", tokens.color_tracer());
|
||||
|
||||
if log_enabled!(target: "nu::color_syntax", log::Level::Debug) {
|
||||
println!("");
|
||||
ptree::print_tree(&tokens.color_tracer().clone().print(Text::from(line)))
|
||||
.unwrap();
|
||||
println!("");
|
||||
}
|
||||
|
||||
for shape in shapes {
|
||||
let styled = paint_flat_shape(&shape, line);
|
||||
out.push_str(&styled);
|
||||
}
|
||||
|
||||
Cow::Owned(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,83 +113,55 @@ impl Highlighter for Helper {
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_token_node(token_node: &TokenNode, line: &str) -> String {
|
||||
let styled = match token_node {
|
||||
TokenNode::Call(..) => Color::Cyan.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Whitespace(..) => Color::White.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Flag(..) => Color::Black.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Member(..) => Color::Yellow.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Path(..) => Color::Green.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Error(..) => Color::Red.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Delimited(..) => Color::White.paint(token_node.tag().slice(line)),
|
||||
TokenNode::Operator(..) => Color::White.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Pipeline(..) => Color::Blue.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Number(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Size(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::GlobPattern,
|
||||
..
|
||||
}) => Color::Cyan.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::String(..),
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Variable(..),
|
||||
..
|
||||
}) => Color::Yellow.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Bare,
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::ExternalCommand(..),
|
||||
..
|
||||
}) => Color::Cyan.bold().paint(token_node.tag().slice(line)),
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::ExternalWord,
|
||||
..
|
||||
}) => Color::Black.bold().paint(token_node.tag().slice(line)),
|
||||
};
|
||||
#[allow(unused)]
|
||||
fn vec_tag<T>(input: Vec<Tagged<T>>) -> Option<Tag> {
|
||||
let mut iter = input.iter();
|
||||
let first = iter.next()?.tag.clone();
|
||||
let last = iter.last();
|
||||
|
||||
styled.to_string()
|
||||
Some(match last {
|
||||
None => first,
|
||||
Some(last) => first.until(&last.tag),
|
||||
})
|
||||
}
|
||||
|
||||
fn paint_pipeline_element(pipeline_element: &PipelineElement, line: &str) -> String {
|
||||
let mut styled = String::new();
|
||||
|
||||
if let Some(_) = pipeline_element.pipe {
|
||||
styled.push_str(&Color::Purple.paint("|"));
|
||||
}
|
||||
|
||||
if let Some(ws) = pipeline_element.pre_ws {
|
||||
styled.push_str(&Color::White.normal().paint(ws.slice(line)));
|
||||
}
|
||||
|
||||
styled.push_str(
|
||||
&Color::Cyan
|
||||
.bold()
|
||||
.paint(pipeline_element.call().head().tag().slice(line))
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
if let Some(children) = pipeline_element.call().children() {
|
||||
for child in children {
|
||||
styled.push_str(&paint_token_node(child, line));
|
||||
fn paint_flat_shape(flat_shape: &Spanned<FlatShape>, line: &str) -> String {
|
||||
let style = match &flat_shape.item {
|
||||
FlatShape::OpenDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::CloseDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::ItVariable => Color::Purple.bold(),
|
||||
FlatShape::Variable => Color::Purple.normal(),
|
||||
FlatShape::Operator => Color::Yellow.normal(),
|
||||
FlatShape::Dot => Color::White.normal(),
|
||||
FlatShape::InternalCommand => Color::Cyan.bold(),
|
||||
FlatShape::ExternalCommand => Color::Cyan.normal(),
|
||||
FlatShape::ExternalWord => Color::Black.bold(),
|
||||
FlatShape::BareMember => Color::Yellow.bold(),
|
||||
FlatShape::StringMember => Color::Yellow.bold(),
|
||||
FlatShape::String => Color::Green.normal(),
|
||||
FlatShape::Path => Color::Cyan.normal(),
|
||||
FlatShape::GlobPattern => Color::Cyan.bold(),
|
||||
FlatShape::Word => Color::Green.normal(),
|
||||
FlatShape::Pipe => Color::Purple.bold(),
|
||||
FlatShape::Flag => Color::Black.bold(),
|
||||
FlatShape::ShorthandFlag => Color::Black.bold(),
|
||||
FlatShape::Int => Color::Purple.bold(),
|
||||
FlatShape::Decimal => Color::Purple.bold(),
|
||||
FlatShape::Whitespace => Color::White.normal(),
|
||||
FlatShape::Error => Color::Red.bold(),
|
||||
FlatShape::Size { number, unit } => {
|
||||
let number = number.slice(line);
|
||||
let unit = unit.slice(line);
|
||||
return format!(
|
||||
"{}{}",
|
||||
Color::Purple.bold().paint(number),
|
||||
Color::Cyan.bold().paint(unit)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(ws) = pipeline_element.post_ws {
|
||||
styled.push_str(&Color::White.normal().paint(ws.slice(line)));
|
||||
}
|
||||
|
||||
styled.to_string()
|
||||
let body = flat_shape.span.slice(line);
|
||||
style.paint(body).to_string()
|
||||
}
|
||||
|
||||
impl rustyline::Helper for Helper {}
|
||||
|
@ -3,20 +3,19 @@ use crate::commands::cp::CopyArgs;
|
||||
use crate::commands::mkdir::MkdirArgs;
|
||||
use crate::commands::mv::MoveArgs;
|
||||
use crate::commands::rm::RemoveArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use crate::stream::OutputStream;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait Shell: std::fmt::Debug {
|
||||
fn name(&self, source_map: &SourceMap) -> String;
|
||||
fn name(&self) -> String;
|
||||
fn homedir(&self) -> Option<PathBuf>;
|
||||
|
||||
fn ls(
|
||||
&self,
|
||||
pattern: Option<Tagged<PathBuf>>,
|
||||
command_tag: Tag,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn cp(&self, args: CopyArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;
|
||||
|
@ -10,18 +10,19 @@ use crate::shell::shell::Shell;
|
||||
use crate::stream::OutputStream;
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShellManager {
|
||||
pub(crate) current_shell: usize,
|
||||
pub(crate) current_shell: Arc<AtomicUsize>,
|
||||
pub(crate) shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
||||
}
|
||||
|
||||
impl ShellManager {
|
||||
pub fn basic(commands: CommandRegistry) -> Result<ShellManager, Box<dyn Error>> {
|
||||
Ok(ShellManager {
|
||||
current_shell: 0,
|
||||
current_shell: Arc::new(AtomicUsize::new(0)),
|
||||
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic(
|
||||
commands,
|
||||
)?)])),
|
||||
@ -30,24 +31,29 @@ impl ShellManager {
|
||||
|
||||
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) {
|
||||
self.shells.lock().unwrap().push(shell);
|
||||
self.current_shell = self.shells.lock().unwrap().len() - 1;
|
||||
self.current_shell
|
||||
.store(self.shells.lock().unwrap().len() - 1, Ordering::SeqCst);
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn current_shell(&self) -> usize {
|
||||
self.current_shell.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn remove_at_current(&mut self) {
|
||||
{
|
||||
let mut shells = self.shells.lock().unwrap();
|
||||
if shells.len() > 0 {
|
||||
if self.current_shell == shells.len() - 1 {
|
||||
if self.current_shell() == shells.len() - 1 {
|
||||
shells.pop();
|
||||
let new_len = shells.len();
|
||||
if new_len > 0 {
|
||||
self.current_shell = new_len - 1;
|
||||
self.current_shell.store(new_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
shells.remove(self.current_shell);
|
||||
shells.remove(self.current_shell());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,17 +65,17 @@ impl ShellManager {
|
||||
}
|
||||
|
||||
pub fn path(&self) -> String {
|
||||
self.shells.lock().unwrap()[self.current_shell].path()
|
||||
self.shells.lock().unwrap()[self.current_shell()].path()
|
||||
}
|
||||
|
||||
pub fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env[self.current_shell].pwd(args)
|
||||
env[self.current_shell()].pwd(args)
|
||||
}
|
||||
|
||||
pub fn set_path(&mut self, path: String) {
|
||||
self.shells.lock().unwrap()[self.current_shell].set_path(path)
|
||||
self.shells.lock().unwrap()[self.current_shell()].set_path(path)
|
||||
}
|
||||
|
||||
pub fn complete(
|
||||
@ -78,20 +84,21 @@ impl ShellManager {
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||
self.shells.lock().unwrap()[self.current_shell].complete(line, pos, ctx)
|
||||
self.shells.lock().unwrap()[self.current_shell()].complete(line, pos, ctx)
|
||||
}
|
||||
|
||||
pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.shells.lock().unwrap()[self.current_shell].hint(line, pos, ctx)
|
||||
self.shells.lock().unwrap()[self.current_shell()].hint(line, pos, ctx)
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
{
|
||||
let shell_len = self.shells.lock().unwrap().len();
|
||||
if self.current_shell == (shell_len - 1) {
|
||||
self.current_shell = 0;
|
||||
if self.current_shell() == (shell_len - 1) {
|
||||
self.current_shell.store(0, Ordering::SeqCst);
|
||||
} else {
|
||||
self.current_shell += 1;
|
||||
self.current_shell
|
||||
.store(self.current_shell() + 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
self.set_path(self.path());
|
||||
@ -100,10 +107,11 @@ impl ShellManager {
|
||||
pub fn prev(&mut self) {
|
||||
{
|
||||
let shell_len = self.shells.lock().unwrap().len();
|
||||
if self.current_shell == 0 {
|
||||
self.current_shell = shell_len - 1;
|
||||
if self.current_shell() == 0 {
|
||||
self.current_shell.store(shell_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
self.current_shell -= 1;
|
||||
self.current_shell
|
||||
.store(self.current_shell() - 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
self.set_path(self.path());
|
||||
@ -112,23 +120,23 @@ impl ShellManager {
|
||||
pub fn homedir(&self) -> Option<PathBuf> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env[self.current_shell].homedir()
|
||||
env[self.current_shell()].homedir()
|
||||
}
|
||||
|
||||
pub fn ls(
|
||||
&self,
|
||||
path: Option<Tagged<PathBuf>>,
|
||||
command_tag: Tag,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env[self.current_shell].ls(path, command_tag)
|
||||
env[self.current_shell()].ls(path, context)
|
||||
}
|
||||
|
||||
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env[self.current_shell].cd(args)
|
||||
env[self.current_shell()].cd(args)
|
||||
}
|
||||
|
||||
pub fn cp(
|
||||
@ -140,13 +148,13 @@ impl ShellManager {
|
||||
|
||||
match env {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell].path();
|
||||
x[self.current_shell].cp(args, context.name, &path)
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].cp(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
context.name,
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -160,13 +168,13 @@ impl ShellManager {
|
||||
|
||||
match env {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell].path();
|
||||
x[self.current_shell].rm(args, context.name, &path)
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].rm(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
context.name,
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -180,13 +188,13 @@ impl ShellManager {
|
||||
|
||||
match env {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell].path();
|
||||
x[self.current_shell].mkdir(args, context.name, &path)
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].mkdir(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
context.name,
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -200,13 +208,13 @@ impl ShellManager {
|
||||
|
||||
match env {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell].path();
|
||||
x[self.current_shell].mv(args, context.name, &path)
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].mv(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
context.name,
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ use crate::commands::cp::CopyArgs;
|
||||
use crate::commands::mkdir::MkdirArgs;
|
||||
use crate::commands::mv::MoveArgs;
|
||||
use crate::commands::rm::RemoveArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::utils::ValueStructure;
|
||||
@ -72,8 +71,8 @@ impl ValueShell {
|
||||
}
|
||||
|
||||
impl Shell for ValueShell {
|
||||
fn name(&self, source_map: &SourceMap) -> String {
|
||||
let anchor_name = self.value.anchor_name(source_map);
|
||||
fn name(&self) -> String {
|
||||
let anchor_name = self.value.anchor_name();
|
||||
format!(
|
||||
"{}",
|
||||
match anchor_name {
|
||||
@ -90,9 +89,10 @@ impl Shell for ValueShell {
|
||||
fn ls(
|
||||
&self,
|
||||
target: Option<Tagged<PathBuf>>,
|
||||
command_name: Tag,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = PathBuf::from(self.path());
|
||||
let name_tag = context.name.clone();
|
||||
|
||||
match &target {
|
||||
Some(value) => full_path.push(value.as_ref()),
|
||||
@ -114,7 +114,7 @@ impl Shell for ValueShell {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not list entries inside",
|
||||
"No such path exists",
|
||||
command_name,
|
||||
name_tag,
|
||||
));
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ impl Shell for ValueShell {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to path inside",
|
||||
"No such path exists",
|
||||
args.call_info.name_tag,
|
||||
&args.call_info.name_tag,
|
||||
));
|
||||
}
|
||||
|
||||
@ -213,10 +213,9 @@ impl Shell for ValueShell {
|
||||
|
||||
fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnSuccess::value(Tagged::from_item(
|
||||
Value::string(self.path()),
|
||||
args.call_info.name_tag,
|
||||
)));
|
||||
stream.push_back(ReturnSuccess::value(
|
||||
Value::string(self.path()).tagged(&args.call_info.name_tag),
|
||||
));
|
||||
Ok(stream.into())
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user