Add value shell

This commit is contained in:
Jonathan Turner 2019-08-07 17:20:09 +12:00
parent e80b198a0b
commit be1976dd18
6 changed files with 211 additions and 10 deletions

View File

@ -145,18 +145,49 @@ impl InternalCommand {
match item? {
ReturnSuccess::Action(action) => match action {
CommandAction::ChangePath(path) => {
context
.shell_manager
.set_path(path.to_string_lossy().to_string());
context.shell_manager.set_path(path);
}
CommandAction::AddSpanSource(uuid, span_source) => {
context.add_span_source(uuid, span_source);
}
CommandAction::Exit => std::process::exit(0),
CommandAction::Enter(location) => {
context
.shell_manager
.push(Box::new(FilesystemShell::with_location(location)?));
let path = std::path::Path::new(&location);
if path.is_dir() {
// If it's a directory, add a new filesystem shell
context
.shell_manager
.push(Box::new(FilesystemShell::with_location(location)?));
} else {
// If it's a file, attempt to open the file as a value and enter it
let cwd = context.shell_manager.path();
let full_path = std::path::PathBuf::from(cwd);
let (file_extension, contents, contents_tag, _) =
crate::commands::open::fetch(
&full_path,
&location,
Span::unknown(),
)?;
match contents {
Value::Primitive(Primitive::String(string)) => {
let value = crate::commands::open::parse_as_value(
file_extension,
string,
contents_tag,
Span::unknown(),
)?;
context.shell_manager.push(Box::new(ValueShell::new(value)));
}
value => context
.shell_manager
.push(Box::new(ValueShell::new(value.tagged(Tag::unknown())))),
}
}
}
CommandAction::PreviousShell => {
context.shell_manager.prev();

View File

@ -6,7 +6,6 @@ use crate::parser::registry::{self, Args};
use crate::prelude::*;
use getset::Getters;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use uuid::Uuid;
#[derive(Deserialize, Serialize, Debug, Clone)]
@ -60,7 +59,7 @@ pub struct SinkCommandArgs {
#[derive(Debug, Serialize, Deserialize)]
pub enum CommandAction {
ChangePath(PathBuf),
ChangePath(String),
AddSpanSource(Uuid, SpanSource),
Exit,
Enter(String),
@ -83,7 +82,7 @@ impl From<Tagged<Value>> for ReturnValue {
}
impl ReturnSuccess {
pub fn change_cwd(path: PathBuf) -> ReturnValue {
pub fn change_cwd(path: String) -> ReturnValue {
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
}

View File

@ -45,6 +45,7 @@ crate use crate::object::types::ExtractType;
crate use crate::object::{Primitive, Value};
crate use crate::shell::filesystem_shell::FilesystemShell;
crate use crate::shell::shell_manager::ShellManager;
crate use crate::shell::value_shell::ValueShell;
crate use crate::stream::{InputStream, OutputStream};
crate use crate::Span;
crate use crate::Text;

View File

@ -3,5 +3,6 @@ crate mod filesystem_shell;
crate mod helper;
crate mod shell;
crate mod shell_manager;
crate mod value_shell;
crate use helper::Helper;

View File

@ -166,7 +166,9 @@ impl Shell for FilesystemShell {
}
}
}
stream.push_back(ReturnSuccess::change_cwd(path));
stream.push_back(ReturnSuccess::change_cwd(
path.to_string_lossy().to_string(),
));
Ok(stream.into())
}

167
src/shell/value_shell.rs Normal file
View File

@ -0,0 +1,167 @@
use crate::commands::command::CallInfo;
use crate::prelude::*;
use crate::shell::shell::Shell;
use rustyline::completion::{self, Completer};
use rustyline::error::ReadlineError;
use rustyline::hint::Hinter;
use std::ffi::OsStr;
use std::path::PathBuf;
#[derive(Clone)]
pub struct ValueShell {
crate path: String,
crate value: Tagged<Value>,
}
impl ValueShell {
pub fn new(value: Tagged<Value>) -> ValueShell {
ValueShell {
path: "/".to_string(),
value,
}
}
fn members(&self) -> VecDeque<Tagged<Value>> {
let mut shell_entries = VecDeque::new();
let full_path = PathBuf::from(&self.path);
let mut viewed = self.value.clone();
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.clone();
}
_ => {}
},
}
}
match viewed {
Tagged {
item: Value::List(l),
..
} => {
for item in l {
shell_entries.push_back(item.clone());
}
}
x => {
shell_entries.push_back(x.clone());
}
}
shell_entries
}
}
impl Shell for ValueShell {
fn ls(&self, _call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
Ok(self
.members()
.map(|x| ReturnSuccess::value(x))
.to_output_stream())
}
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
let path = match call_info.args.nth(0) {
None => "/".to_string(),
Some(v) => {
let target = v.as_string()?;
let mut cwd = PathBuf::from(&self.path);
match target {
x if x == ".." => {
cwd.pop();
}
_ => match target.chars().nth(0) {
Some(x) if x == '/' => cwd = PathBuf::from(target),
_ => {
cwd.push(target);
}
},
}
cwd.to_string_lossy().to_string()
}
};
let mut stream = VecDeque::new();
stream.push_back(ReturnSuccess::change_cwd(path));
Ok(stream.into())
}
fn path(&self) -> String {
self.path.clone()
}
fn set_path(&mut self, path: String) {
let _ = std::env::set_current_dir(&path);
self.path = path.clone();
}
}
impl Completer for ValueShell {
type Candidate = completion::Pair;
fn complete(
&self,
line: &str,
pos: usize,
_ctx: &rustyline::Context<'_>,
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
let mut completions = vec![];
//let commands = vec!["testme", "whatever"];
let mut possible_completion = vec![];
let members = self.members();
for member in members {
match member {
Tagged { item, .. } => {
for desc in item.data_descriptors() {
possible_completion.push(desc);
}
}
}
}
let line_chars: Vec<_> = line.chars().collect();
let mut replace_pos = pos;
while replace_pos > 0 {
if line_chars[replace_pos - 1] == ' ' {
break;
}
replace_pos -= 1;
}
for command in possible_completion.iter() {
let mut pos = replace_pos;
let mut matched = true;
if pos < line_chars.len() {
for chr in command.chars() {
if line_chars[pos] != chr {
matched = false;
break;
}
pos += 1;
if pos == line_chars.len() {
break;
}
}
}
if matched {
completions.push(completion::Pair {
display: command.to_string(),
replacement: command.to_string(),
});
}
}
Ok((replace_pos, completions))
}
}
impl Hinter for ValueShell {
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
None
}
}