forked from extern/nushell
Better cd and ls
This commit is contained in:
parent
407b4ddb53
commit
f40089f29b
26
src/cli.rs
26
src/cli.rs
@ -60,6 +60,8 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
command("from-yaml", from_yaml::from_yaml),
|
command("from-yaml", from_yaml::from_yaml),
|
||||||
command("get", get::get),
|
command("get", get::get),
|
||||||
command("open", open::open),
|
command("open", open::open),
|
||||||
|
command("enter", enter::enter),
|
||||||
|
command("exit", exit::exit),
|
||||||
command("pick", pick::pick),
|
command("pick", pick::pick),
|
||||||
command("split-column", split_column::split_column),
|
command("split-column", split_column::split_column),
|
||||||
command("split-row", split_row::split_row),
|
command("split-row", split_row::split_row),
|
||||||
@ -109,14 +111,22 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let readline = rl.readline(&format!(
|
let (obj, cwd) = {
|
||||||
"{}{}> ",
|
let env = context.env.lock().unwrap();
|
||||||
context.env.lock().unwrap().cwd().display(),
|
let last = env.last().unwrap();
|
||||||
match current_branch() {
|
(last.obj().clone(), last.path().display().to_string())
|
||||||
Some(s) => format!("({})", s),
|
};
|
||||||
None => "".to_string(),
|
let readline = match obj {
|
||||||
}
|
Value::Filesystem => rl.readline(&format!(
|
||||||
));
|
"{}{}> ",
|
||||||
|
cwd,
|
||||||
|
match current_branch() {
|
||||||
|
Some(s) => format!("({})", s),
|
||||||
|
None => "".to_string(),
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
_ => rl.readline(&format!("{}{}> ", obj.type_name(), cwd)),
|
||||||
|
};
|
||||||
|
|
||||||
match process_line(readline, &mut context).await {
|
match process_line(readline, &mut context).await {
|
||||||
LineResult::Success(line) => {
|
LineResult::Success(line) => {
|
||||||
|
@ -5,6 +5,8 @@ crate mod classified;
|
|||||||
crate mod clip;
|
crate mod clip;
|
||||||
crate mod command;
|
crate mod command;
|
||||||
crate mod config;
|
crate mod config;
|
||||||
|
crate mod enter;
|
||||||
|
crate mod exit;
|
||||||
crate mod first;
|
crate mod first;
|
||||||
crate mod from_json;
|
crate mod from_json;
|
||||||
crate mod from_toml;
|
crate mod from_toml;
|
||||||
|
@ -1,44 +1,77 @@
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let env = args.env.lock().unwrap();
|
||||||
let path = match args.positional.first() {
|
let latest = env.last().unwrap();
|
||||||
None => match dirs::home_dir() {
|
|
||||||
Some(o) => o,
|
match latest.obj {
|
||||||
_ => return Err(ShellError::string("Can not change to home directory")),
|
Value::Filesystem => {
|
||||||
},
|
let cwd = latest.path().to_path_buf();
|
||||||
Some(v) => {
|
let path = match args.positional.first() {
|
||||||
let target = v.as_string()?.clone();
|
None => match dirs::home_dir() {
|
||||||
match dunce::canonicalize(cwd.join(&target).as_path()) {
|
Some(o) => o,
|
||||||
Ok(p) => p,
|
_ => return Err(ShellError::string("Can not change to home directory")),
|
||||||
|
},
|
||||||
|
Some(v) => {
|
||||||
|
let target = v.as_string()?.clone();
|
||||||
|
match dunce::canonicalize(cwd.join(&target).as_path()) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Can not change to directory",
|
||||||
|
"directory not found",
|
||||||
|
args.positional[0].span.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stream = VecDeque::new();
|
||||||
|
match env::set_current_dir(&path) {
|
||||||
|
Ok(_) => {}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(ShellError::labeled_error(
|
if args.positional.len() > 0 {
|
||||||
"Can not change to directory",
|
return Err(ShellError::labeled_error(
|
||||||
"directory not found",
|
"Can not change to directory",
|
||||||
args.positional[0].span.clone(),
|
"directory not found",
|
||||||
));
|
args.positional[0].span.clone(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::string("Can not change to directory"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stream.push_back(ReturnValue::change_cwd(path));
|
||||||
|
Ok(stream.boxed())
|
||||||
}
|
}
|
||||||
};
|
_ => {
|
||||||
|
let mut stream = VecDeque::new();
|
||||||
let mut stream = VecDeque::new();
|
match args.positional.first() {
|
||||||
match env::set_current_dir(&path) {
|
None => {
|
||||||
Ok(_) => {}
|
stream.push_back(ReturnValue::change_cwd(PathBuf::from("/")));
|
||||||
Err(_) => {
|
}
|
||||||
if args.positional.len() > 0 {
|
Some(v) => {
|
||||||
return Err(ShellError::labeled_error(
|
let mut cwd = latest.path().to_path_buf();
|
||||||
"Can not change to directory",
|
let target = v.as_string()?.clone();
|
||||||
"directory not found",
|
match target {
|
||||||
args.positional[0].span.clone(),
|
x if x == ".." => {
|
||||||
));
|
cwd.pop();
|
||||||
} else {
|
}
|
||||||
return Err(ShellError::string("Can not change to directory"));
|
_ => match target.chars().nth(0) {
|
||||||
}
|
Some(x) if x == '/' => cwd = PathBuf::from(target),
|
||||||
|
_ => {
|
||||||
|
cwd.push(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
stream.push_back(ReturnValue::change_cwd(cwd));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(stream.boxed())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.push_back(ReturnValue::change_cwd(path));
|
|
||||||
Ok(stream.boxed())
|
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ use crate::prelude::*;
|
|||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures_codec::{Decoder, Encoder, Framed};
|
use futures_codec::{Decoder, Encoder, Framed};
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use subprocess::Exec;
|
use subprocess::Exec;
|
||||||
|
|
||||||
/// A simple `Codec` implementation that splits up data into lines.
|
/// A simple `Codec` implementation that splits up data into lines.
|
||||||
pub struct LinesCodec {}
|
pub struct LinesCodec {}
|
||||||
|
|
||||||
@ -119,8 +119,23 @@ impl InternalCommand {
|
|||||||
|
|
||||||
let stream = result.filter_map(move |v| match v {
|
let stream = result.filter_map(move |v| match v {
|
||||||
ReturnValue::Action(action) => match action {
|
ReturnValue::Action(action) => match action {
|
||||||
CommandAction::ChangeCwd(cwd) => {
|
CommandAction::ChangePath(path) => {
|
||||||
env.lock().unwrap().cwd = cwd;
|
env.lock().unwrap().last_mut().map(|x| {
|
||||||
|
x.path = path;
|
||||||
|
x
|
||||||
|
});
|
||||||
|
futures::future::ready(None)
|
||||||
|
}
|
||||||
|
CommandAction::Enter(obj) => {
|
||||||
|
let new_env = Environment {
|
||||||
|
obj: obj,
|
||||||
|
path: PathBuf::from("/"),
|
||||||
|
};
|
||||||
|
env.lock().unwrap().push(new_env);
|
||||||
|
futures::future::ready(None)
|
||||||
|
}
|
||||||
|
CommandAction::Exit => {
|
||||||
|
let _ = env.lock().unwrap().pop();
|
||||||
futures::future::ready(None)
|
futures::future::ready(None)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -210,7 +225,7 @@ impl ExternalCommand {
|
|||||||
}
|
}
|
||||||
process = Exec::shell(new_arg_string);
|
process = Exec::shell(new_arg_string);
|
||||||
}
|
}
|
||||||
process = process.cwd(context.env.lock().unwrap().cwd());
|
process = process.cwd(context.env.lock().unwrap().first().unwrap().path());
|
||||||
|
|
||||||
let mut process = match stream_next {
|
let mut process = match stream_next {
|
||||||
StreamNext::Last => process,
|
StreamNext::Last => process,
|
||||||
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
pub struct CommandArgs {
|
pub struct CommandArgs {
|
||||||
pub host: Arc<Mutex<dyn Host + Send>>,
|
pub host: Arc<Mutex<dyn Host + Send>>,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub env: Arc<Mutex<Vec<Environment>>>,
|
||||||
pub name_span: Option<Span>,
|
pub name_span: Option<Span>,
|
||||||
pub positional: Vec<Spanned<Value>>,
|
pub positional: Vec<Spanned<Value>>,
|
||||||
pub named: indexmap::IndexMap<String, Value>,
|
pub named: indexmap::IndexMap<String, Value>,
|
||||||
@ -25,7 +25,9 @@ pub struct SinkCommandArgs {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CommandAction {
|
pub enum CommandAction {
|
||||||
ChangeCwd(PathBuf),
|
ChangePath(PathBuf),
|
||||||
|
Enter(Value),
|
||||||
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -36,7 +38,7 @@ pub enum ReturnValue {
|
|||||||
|
|
||||||
impl ReturnValue {
|
impl ReturnValue {
|
||||||
crate fn change_cwd(path: PathBuf) -> ReturnValue {
|
crate fn change_cwd(path: PathBuf) -> ReturnValue {
|
||||||
ReturnValue::Action(CommandAction::ChangeCwd(path))
|
ReturnValue::Action(CommandAction::ChangePath(path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
137
src/commands/enter.rs
Normal file
137
src/commands/enter.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use crate::commands::command::CommandAction;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::{Primitive, Value};
|
||||||
|
use crate::parser::lexer::Spanned;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
if args.positional.len() == 0 {
|
||||||
|
return Err(ShellError::string("open requires a filepath or url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let cwd = args
|
||||||
|
.env
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
|
let mut full_path = PathBuf::from(cwd);
|
||||||
|
|
||||||
|
let (file_extension, contents) = match &args.positional[0].item {
|
||||||
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
|
if s.starts_with("http:") || s.starts_with("https:") {
|
||||||
|
let response = reqwest::get(s);
|
||||||
|
match response {
|
||||||
|
Ok(mut r) => match r.text() {
|
||||||
|
Ok(s) => {
|
||||||
|
let fname = r
|
||||||
|
.url()
|
||||||
|
.path_segments()
|
||||||
|
.and_then(|segments| segments.last())
|
||||||
|
.and_then(|name| if name.is_empty() { None } else { Some(name) })
|
||||||
|
.and_then(|name| {
|
||||||
|
PathBuf::from(name)
|
||||||
|
.extension()
|
||||||
|
.map(|name| name.to_string_lossy().to_string())
|
||||||
|
});
|
||||||
|
(fname, s)
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Web page contents corrupt",
|
||||||
|
"received garbled data",
|
||||||
|
args.positional[0].span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"URL could not be opened",
|
||||||
|
"url not found",
|
||||||
|
args.positional[0].span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
full_path.push(Path::new(&s));
|
||||||
|
match std::fs::read_to_string(&full_path) {
|
||||||
|
Ok(s) => (
|
||||||
|
full_path
|
||||||
|
.extension()
|
||||||
|
.map(|name| name.to_string_lossy().to_string()),
|
||||||
|
s,
|
||||||
|
),
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"File cound not be opened",
|
||||||
|
"file not found",
|
||||||
|
args.positional[0].span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Expected string value for filename",
|
||||||
|
"expected filename",
|
||||||
|
args.positional[0].span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stream = VecDeque::new();
|
||||||
|
|
||||||
|
let open_raw = match args.positional.get(1) {
|
||||||
|
Some(Spanned {
|
||||||
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
|
..
|
||||||
|
}) if s == "--raw" => true,
|
||||||
|
Some(v) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Unknown flag for open",
|
||||||
|
"unknown flag",
|
||||||
|
v.span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
match file_extension {
|
||||||
|
Some(x) if x == "toml" && !open_raw => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||||
|
crate::commands::from_toml::from_toml_string_to_value(contents),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Some(x) if x == "json" && !open_raw => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||||
|
crate::commands::from_json::from_json_string_to_value(contents),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Some(x) if x == "xml" && !open_raw => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||||
|
crate::commands::from_xml::from_xml_string_to_value(contents),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Some(x) if x == "yml" && !open_raw => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||||
|
crate::commands::from_yaml::from_yaml_string_to_value(contents),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Some(x) if x == "yaml" && !open_raw => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(
|
||||||
|
crate::commands::from_yaml::from_yaml_string_to_value(contents),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Enter(Value::Primitive(
|
||||||
|
Primitive::String(contents),
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(stream.boxed())
|
||||||
|
}
|
12
src/commands/exit.rs
Normal file
12
src/commands/exit.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::commands::command::CommandAction;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::{Primitive, Value};
|
||||||
|
use crate::parser::lexer::Spanned;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn exit(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let mut stream = VecDeque::new();
|
||||||
|
stream.push_back(ReturnValue::Action(CommandAction::Exit));
|
||||||
|
Ok(stream.boxed())
|
||||||
|
}
|
@ -2,11 +2,14 @@ use crate::errors::ShellError;
|
|||||||
use crate::object::{dir_entry_dict, Primitive, Value};
|
use crate::object::{dir_entry_dict, Primitive, Value};
|
||||||
use crate::parser::lexer::Spanned;
|
use crate::parser::lexer::Spanned;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let env = args.env.lock().unwrap();
|
||||||
let mut full_path = PathBuf::from(cwd);
|
let path = env.last().unwrap().path.to_path_buf();
|
||||||
|
let obj = &env.last().unwrap().obj;
|
||||||
|
let mut full_path = PathBuf::from(path);
|
||||||
match &args.positional.get(0) {
|
match &args.positional.get(0) {
|
||||||
Some(Spanned {
|
Some(Spanned {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
@ -15,29 +18,60 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries = std::fs::read_dir(&full_path);
|
match obj {
|
||||||
|
Value::Filesystem => {
|
||||||
|
let entries = std::fs::read_dir(&full_path);
|
||||||
|
|
||||||
let entries = match entries {
|
let entries = match entries {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Some(s) = args.positional.get(0) {
|
if let Some(s) = args.positional.get(0) {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
s.span,
|
s.span,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::string(e.to_string()));
|
return Err(ShellError::string(e.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut shell_entries = VecDeque::new();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
let value = Value::Object(dir_entry_dict(&entry?)?);
|
||||||
|
shell_entries.push_back(ReturnValue::Value(value))
|
||||||
}
|
}
|
||||||
|
Ok(shell_entries.boxed())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut entries = VecDeque::new();
|
||||||
|
let mut viewed = obj;
|
||||||
|
let sep_string = std::path::MAIN_SEPARATOR.to_string();
|
||||||
|
let sep = OsStr::new(&sep_string);
|
||||||
|
for p in full_path.iter() {
|
||||||
|
match p {
|
||||||
|
x if x == sep => {}
|
||||||
|
step => match viewed.get_data_by_key(step.to_str().unwrap()) {
|
||||||
|
Some(v) => {
|
||||||
|
viewed = v;
|
||||||
|
}
|
||||||
|
_ => println!("Obj not Some"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match viewed {
|
||||||
|
Value::List(l) => {
|
||||||
|
for item in l {
|
||||||
|
entries.push_back(ReturnValue::Value(item.copy()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
entries.push_back(ReturnValue::Value(x.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(entries.boxed())
|
||||||
}
|
}
|
||||||
Ok(o) => o,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut shell_entries = VecDeque::new();
|
|
||||||
|
|
||||||
for entry in entries {
|
|
||||||
let value = Value::Object(dir_entry_dict(&entry?)?);
|
|
||||||
shell_entries.push_back(ReturnValue::Value(value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(shell_entries.boxed())
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,14 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
return Err(ShellError::string("open requires a filepath or url"));
|
return Err(ShellError::string("open requires a filepath or url"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args
|
||||||
|
.env
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
let mut full_path = PathBuf::from(cwd);
|
let mut full_path = PathBuf::from(cwd);
|
||||||
|
|
||||||
let (file_extension, contents) = match &args.positional[0].item {
|
let (file_extension, contents) = match &args.positional[0].item {
|
||||||
|
@ -9,7 +9,15 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||||||
return Err(ShellError::string("save requires a filepath"));
|
return Err(ShellError::string("save requires a filepath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = args.ctx.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args
|
||||||
|
.ctx
|
||||||
|
.env
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
let mut full_path = PathBuf::from(cwd);
|
let mut full_path = PathBuf::from(cwd);
|
||||||
match &(args.positional[0].item) {
|
match &(args.positional[0].item) {
|
||||||
Value::Primitive(Primitive::String(s)) => full_path.push(Path::new(s)),
|
Value::Primitive(Primitive::String(s)) => full_path.push(Path::new(s)),
|
||||||
|
@ -9,7 +9,14 @@ pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
if args.positional.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("size requires at least one file"));
|
return Err(ShellError::string("size requires at least one file"));
|
||||||
}
|
}
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args
|
||||||
|
.env
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
|
||||||
|
@ -30,7 +30,14 @@ pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args
|
||||||
|
.env
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
let printer = PrettyPrinter::default()
|
let printer = PrettyPrinter::default()
|
||||||
.line_numbers(false)
|
.line_numbers(false)
|
||||||
|
@ -13,7 +13,7 @@ pub struct Context {
|
|||||||
commands: IndexMap<String, Arc<dyn Command>>,
|
commands: IndexMap<String, Arc<dyn Command>>,
|
||||||
sinks: IndexMap<String, Arc<dyn Sink>>,
|
sinks: IndexMap<String, Arc<dyn Sink>>,
|
||||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||||
crate env: Arc<Mutex<Environment>>,
|
crate env: Arc<Mutex<Vec<Environment>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
@ -22,7 +22,7 @@ impl Context {
|
|||||||
commands: indexmap::IndexMap::new(),
|
commands: indexmap::IndexMap::new(),
|
||||||
sinks: indexmap::IndexMap::new(),
|
sinks: indexmap::IndexMap::new(),
|
||||||
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
||||||
env: Arc::new(Mutex::new(Environment::basic()?)),
|
env: Arc::new(Mutex::new(vec![Environment::basic()?])),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/env/environment.rs
vendored
19
src/env/environment.rs
vendored
@ -1,18 +1,27 @@
|
|||||||
|
use crate::object::base::Value;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
crate cwd: PathBuf,
|
crate obj: Value,
|
||||||
|
crate path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
pub fn basic() -> Result<Environment, std::io::Error> {
|
pub fn basic() -> Result<Environment, std::io::Error> {
|
||||||
let cwd = std::env::current_dir()?;
|
let path = std::env::current_dir()?;
|
||||||
|
|
||||||
Ok(Environment { cwd })
|
Ok(Environment {
|
||||||
|
obj: Value::Filesystem,
|
||||||
|
path,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cwd(&self) -> &Path {
|
pub fn path(&self) -> &Path {
|
||||||
self.cwd.as_path()
|
self.path.as_path()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn obj(&self) -> &Value {
|
||||||
|
&self.obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,11 @@ impl RenderView for GenericView<'value> {
|
|||||||
host.stdout(&format!("{:?}", e));
|
host.stdout(&format!("{:?}", e));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Filesystem => {
|
||||||
|
host.stdout("<filesystem>");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ impl TreeView {
|
|||||||
}
|
}
|
||||||
Value::Block(_) => {}
|
Value::Block(_) => {}
|
||||||
Value::Error(_) => {}
|
Value::Error(_) => {}
|
||||||
|
Value::Filesystem => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate fn from_value(value: &Value) -> TreeView {
|
crate fn from_value(value: &Value) -> TreeView {
|
||||||
|
@ -154,6 +154,7 @@ pub enum Value {
|
|||||||
Object(crate::object::Dictionary),
|
Object(crate::object::Dictionary),
|
||||||
List(Vec<Value>),
|
List(Vec<Value>),
|
||||||
Block(Block),
|
Block(Block),
|
||||||
|
Filesystem,
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Error(Box<ShellError>),
|
Error(Box<ShellError>),
|
||||||
@ -167,6 +168,7 @@ impl Value {
|
|||||||
Value::List(_) => format!("list"),
|
Value::List(_) => format!("list"),
|
||||||
Value::Block(_) => format!("block"),
|
Value::Block(_) => format!("block"),
|
||||||
Value::Error(_) => format!("error"),
|
Value::Error(_) => format!("error"),
|
||||||
|
Value::Filesystem => format!("filesystem"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +179,7 @@ impl Value {
|
|||||||
Value::Block(_) => vec![DataDescriptor::value_of()],
|
Value::Block(_) => vec![DataDescriptor::value_of()],
|
||||||
Value::List(_) => vec![],
|
Value::List(_) => vec![],
|
||||||
Value::Error(_) => vec![DataDescriptor::value_of()],
|
Value::Error(_) => vec![DataDescriptor::value_of()],
|
||||||
|
Value::Filesystem => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +192,7 @@ impl Value {
|
|||||||
Value::Object(o) => match o.get_data_by_key(name) {
|
Value::Object(o) => match o.get_data_by_key(name) {
|
||||||
Some(v) => return Some(v),
|
Some(v) => return Some(v),
|
||||||
None => {}
|
None => {}
|
||||||
}
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,6 +205,7 @@ impl Value {
|
|||||||
crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
||||||
match self {
|
match self {
|
||||||
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
|
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
|
||||||
|
p @ Value::Filesystem => MaybeOwned::Borrowed(p),
|
||||||
Value::Object(o) => o.get_data(desc),
|
Value::Object(o) => o.get_data(desc),
|
||||||
Value::Block(_) => MaybeOwned::Owned(Value::nothing()),
|
Value::Block(_) => MaybeOwned::Owned(Value::nothing()),
|
||||||
Value::List(_) => MaybeOwned::Owned(Value::nothing()),
|
Value::List(_) => MaybeOwned::Owned(Value::nothing()),
|
||||||
@ -219,6 +223,7 @@ impl Value {
|
|||||||
Value::List(list)
|
Value::List(list)
|
||||||
}
|
}
|
||||||
Value::Error(e) => Value::Error(Box::new(e.copy_error())),
|
Value::Error(e) => Value::Error(Box::new(e.copy_error())),
|
||||||
|
Value::Filesystem => Value::Filesystem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +234,7 @@ impl Value {
|
|||||||
Value::Object(_) => format!("[object Object]"),
|
Value::Object(_) => format!("[object Object]"),
|
||||||
Value::List(_) => format!("[list List]"),
|
Value::List(_) => format!("[list List]"),
|
||||||
Value::Error(e) => format!("{}", e),
|
Value::Error(e) => format!("{}", e),
|
||||||
|
Value::Filesystem => format!("<filesystem>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ impl Serialize for Value {
|
|||||||
Value::List(l) => l.serialize(serializer),
|
Value::List(l) => l.serialize(serializer),
|
||||||
Value::Block(b) => b.serialize(serializer),
|
Value::Block(b) => b.serialize(serializer),
|
||||||
Value::Error(e) => e.serialize(serializer),
|
Value::Error(e) => e.serialize(serializer),
|
||||||
|
Value::Filesystem => "".serialize(serializer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user