mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 04:05:31 +02:00
objectshell initial commit
This commit is contained in:
3
src/commands.rs
Normal file
3
src/commands.rs
Normal file
@ -0,0 +1,3 @@
|
||||
crate mod command;
|
||||
crate mod ls;
|
||||
crate mod ps;
|
10
src/commands/command.rs
Normal file
10
src/commands/command.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
|
||||
pub trait Command {
|
||||
fn run(
|
||||
&mut self,
|
||||
host: &dyn crate::Host,
|
||||
env: &mut crate::Environment,
|
||||
) -> Result<Value, ShellError>;
|
||||
}
|
28
src/commands/ls.rs
Normal file
28
src/commands/ls.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::process::Process;
|
||||
use crate::object::{DirEntry, ShellObject, Value};
|
||||
use derive_new::new;
|
||||
use sysinfo::SystemExt;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Ls;
|
||||
|
||||
impl crate::Command for Ls {
|
||||
fn run(
|
||||
&mut self,
|
||||
_host: &dyn crate::Host,
|
||||
env: &mut crate::Environment,
|
||||
) -> Result<Value, ShellError> {
|
||||
let entries =
|
||||
std::fs::read_dir(env.cwd()).map_err((|e| ShellError::new(format!("{:?}", e))))?;
|
||||
|
||||
let mut shell_entries = vec![];
|
||||
|
||||
for entry in entries {
|
||||
let value = Value::object(DirEntry::new(entry?)?);
|
||||
shell_entries.push(value)
|
||||
}
|
||||
|
||||
Ok(Value::list(shell_entries))
|
||||
}
|
||||
}
|
30
src/commands/ps.rs
Normal file
30
src/commands/ps.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::process::Process;
|
||||
use crate::object::{ShellObject, Value};
|
||||
use derive_new::new;
|
||||
use sysinfo::SystemExt;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Ps {
|
||||
system: sysinfo::System,
|
||||
}
|
||||
|
||||
impl crate::Command for Ps {
|
||||
fn run(
|
||||
&mut self,
|
||||
_host: &dyn crate::Host,
|
||||
_env: &mut crate::Environment,
|
||||
) -> Result<Value, ShellError> {
|
||||
self.system.refresh_all();
|
||||
|
||||
let list = self.system.get_process_list();
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| Value::Object(Box::new(Process::new(process.clone()))))
|
||||
.take(5)
|
||||
.collect();
|
||||
|
||||
Ok(Value::List(list))
|
||||
}
|
||||
}
|
5
src/env.rs
Normal file
5
src/env.rs
Normal file
@ -0,0 +1,5 @@
|
||||
crate mod environment;
|
||||
crate mod host;
|
||||
|
||||
crate use self::environment::Environment;
|
||||
crate use self::host::Host;
|
17
src/env/environment.rs
vendored
Normal file
17
src/env/environment.rs
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Environment {
|
||||
cwd: PathBuf,
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
pub fn basic() -> Result<Environment, std::io::Error> {
|
||||
let cwd = std::env::current_dir()?;
|
||||
|
||||
Ok(Environment { cwd })
|
||||
}
|
||||
|
||||
pub fn cwd(&self) -> &Path {
|
||||
self.cwd.as_path()
|
||||
}
|
||||
}
|
11
src/env/host.rs
vendored
Normal file
11
src/env/host.rs
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
pub trait Host {
|
||||
fn stdout(&mut self, out: &str);
|
||||
}
|
||||
|
||||
crate struct BasicHost;
|
||||
|
||||
impl Host for BasicHost {
|
||||
fn stdout(&mut self, out: &str) {
|
||||
println!("{}", out)
|
||||
}
|
||||
}
|
22
src/errors.rs
Normal file
22
src/errors.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(Debug, new)]
|
||||
pub struct ShellError {
|
||||
title: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ShellError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.title)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ShellError {}
|
||||
|
||||
impl std::convert::From<std::io::Error> for ShellError {
|
||||
fn from(input: std::io::Error) -> ShellError {
|
||||
ShellError {
|
||||
title: format!("{}", input),
|
||||
}
|
||||
}
|
||||
}
|
16
src/format.rs
Normal file
16
src/format.rs
Normal file
@ -0,0 +1,16 @@
|
||||
crate mod entries;
|
||||
crate mod generic;
|
||||
crate mod list;
|
||||
crate mod table;
|
||||
|
||||
use crate::object::Value;
|
||||
use crate::Host;
|
||||
|
||||
crate use entries::EntriesView;
|
||||
crate use generic::GenericView;
|
||||
crate use list::ListView;
|
||||
crate use table::TableView;
|
||||
|
||||
crate trait RenderView {
|
||||
fn render_view(&self, host: &dyn Host) -> Vec<String>;
|
||||
}
|
28
src/format/entries.rs
Normal file
28
src/format/entries.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use crate::format::RenderView;
|
||||
use crate::Host;
|
||||
use derive_new::new;
|
||||
|
||||
// An entries list is printed like this:
|
||||
//
|
||||
// name : ...
|
||||
// name2 : ...
|
||||
// another_name : ...
|
||||
#[derive(new)]
|
||||
pub struct EntriesView {
|
||||
entries: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl RenderView for EntriesView {
|
||||
fn render_view(&self, host: &dyn Host) -> Vec<String> {
|
||||
if self.entries.len() == 0 {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let max_name_size: usize = self.entries.iter().map(|(n, _)| n.len()).max().unwrap();
|
||||
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{:width$} : {}", k, v, width = max_name_size))
|
||||
.collect()
|
||||
}
|
||||
}
|
48
src/format/generic.rs
Normal file
48
src/format/generic.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::format::{RenderView, TableView};
|
||||
use crate::object::base::ToEntriesView;
|
||||
use crate::object::Value;
|
||||
use crate::Host;
|
||||
use derive_new::new;
|
||||
|
||||
// A list is printed one line at a time with an optional separator between groups
|
||||
#[derive(new)]
|
||||
pub struct GenericView<'value> {
|
||||
value: &'value Value,
|
||||
}
|
||||
|
||||
impl RenderView for GenericView<'value> {
|
||||
fn render_view(&self, host: &dyn Host) -> Vec<String> {
|
||||
match self.value {
|
||||
Value::Primitive(p) => vec![p.format()],
|
||||
Value::List(l) => {
|
||||
let view = TableView::from_list(l);
|
||||
|
||||
if let Some(view) = view {
|
||||
view.render_view(host)
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
// let mut list: Vec<String> = vec![];
|
||||
// for item in l {
|
||||
// match item {
|
||||
// Value::Primitive(p) => list.push(p.format()),
|
||||
// Value::List(l) => list.push(format!("{:?}", l)),
|
||||
// Value::Object(o) => {
|
||||
// let view = o.to_entries_view();
|
||||
// let out = view.render_view(host);
|
||||
// list.extend(out);
|
||||
// }
|
||||
// }
|
||||
// list.push("\n".to_string());
|
||||
// }
|
||||
// list
|
||||
}
|
||||
|
||||
Value::Object(o) => {
|
||||
let view = o.to_entries_view();
|
||||
let out = view.render_view(host);
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/format/list.rs
Normal file
23
src/format/list.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::format::RenderView;
|
||||
use crate::Host;
|
||||
use derive_new::new;
|
||||
|
||||
// A list is printed one line at a time with an optional separator between groups
|
||||
#[derive(new)]
|
||||
pub struct ListView {
|
||||
list: Vec<Vec<String>>,
|
||||
sep: String,
|
||||
}
|
||||
|
||||
impl RenderView for ListView {
|
||||
fn render_view(&self, host: &dyn Host) -> Vec<String> {
|
||||
let mut out = vec![];
|
||||
|
||||
for output in &self.list {
|
||||
let string: String = output.iter().map(|l| format!("{}\n", l)).collect();
|
||||
out.push(format!("{}{}", string, self.sep));
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
}
|
65
src/format/table.rs
Normal file
65
src/format/table.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use crate::format::RenderView;
|
||||
use crate::object::ShellObject;
|
||||
use crate::object::Value;
|
||||
use crate::Host;
|
||||
use derive_new::new;
|
||||
use prettytable::{Cell, Row, Table};
|
||||
|
||||
// An entries list is printed like this:
|
||||
//
|
||||
// name : ...
|
||||
// name2 : ...
|
||||
// another_name : ...
|
||||
#[derive(new)]
|
||||
pub struct TableView {
|
||||
headers: Vec<String>,
|
||||
entries: Vec<Vec<String>>,
|
||||
}
|
||||
|
||||
impl TableView {
|
||||
pub fn from_list(values: &[Value]) -> Option<TableView> {
|
||||
if values.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let item = &values[0];
|
||||
let descs = item.data_descriptors();
|
||||
|
||||
let headers = descs.iter().map(|d| d.name.clone()).collect();
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
for value in values {
|
||||
let row = descs
|
||||
.iter()
|
||||
.map(|d| value.get_data(d).borrow().format_leaf())
|
||||
.collect();
|
||||
|
||||
entries.push(row);
|
||||
}
|
||||
|
||||
Some(TableView { headers, entries })
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderView for TableView {
|
||||
fn render_view(&self, host: &dyn Host) -> Vec<String> {
|
||||
if self.entries.len() == 0 {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
let header: Vec<Cell> = self.headers.iter().map(|h| Cell::new(h)).collect();
|
||||
|
||||
table.add_row(Row::new(header));
|
||||
|
||||
for row in &self.entries {
|
||||
table.add_row(Row::new(row.iter().map(|h| Cell::new(h)).collect()));
|
||||
}
|
||||
|
||||
let mut out = vec![];
|
||||
table.print(&mut out).unwrap();
|
||||
|
||||
vec![String::from_utf8_lossy(&out).to_string()]
|
||||
}
|
||||
}
|
94
src/main.rs
Normal file
94
src/main.rs
Normal file
@ -0,0 +1,94 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![allow(unused)]
|
||||
|
||||
mod commands;
|
||||
mod env;
|
||||
mod errors;
|
||||
mod format;
|
||||
mod object;
|
||||
|
||||
crate use crate::commands::command::Command;
|
||||
crate use crate::env::{Environment, Host};
|
||||
crate use crate::format::RenderView;
|
||||
use crate::object::base::{ToEntriesView, ToGenericView};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
use std::collections::BTreeMap;
|
||||
use std::error::Error;
|
||||
use sysinfo::{self, SystemExt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MaybeOwned<'a, T> {
|
||||
Owned(T),
|
||||
Borrowed(&'a T),
|
||||
}
|
||||
|
||||
impl<T> MaybeOwned<'a, T> {
|
||||
crate fn borrow(&self) -> &T {
|
||||
match self {
|
||||
MaybeOwned::Owned(v) => v,
|
||||
MaybeOwned::Borrowed(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
let mut rl = Editor::<()>::new();
|
||||
if rl.load_history("history.txt").is_err() {
|
||||
println!("No previous history.");
|
||||
}
|
||||
|
||||
let mut host = crate::env::host::BasicHost;
|
||||
let mut env = crate::Environment::basic()?;
|
||||
|
||||
let mut commands = BTreeMap::<String, Box<dyn crate::Command>>::new();
|
||||
|
||||
let mut system = sysinfo::System::new();
|
||||
let mut ps = crate::commands::ps::Ps::new(system);
|
||||
let mut ls = crate::commands::ls::Ls;
|
||||
|
||||
commands.insert("ps".to_string(), Box::new(ps));
|
||||
commands.insert("ls".to_string(), Box::new(ls));
|
||||
|
||||
loop {
|
||||
let readline = rl.readline(">> ");
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
rl.add_history_entry(line.as_ref());
|
||||
|
||||
match commands.get_mut(&line) {
|
||||
Some(command) => {
|
||||
let result = command.run(&mut host, &mut env).unwrap();
|
||||
let view = result.to_generic_view();
|
||||
let rendered = view.render_view(&mut host);
|
||||
|
||||
for line in rendered {
|
||||
match line.as_ref() {
|
||||
"\n" => println!(""),
|
||||
line => println!("{}", line),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => println!("Saw: {}", line),
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rl.save_history("history.txt").unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
11
src/object.rs
Normal file
11
src/object.rs
Normal file
@ -0,0 +1,11 @@
|
||||
crate mod base;
|
||||
crate mod desc;
|
||||
crate mod dict;
|
||||
crate mod files;
|
||||
crate mod process;
|
||||
crate mod types;
|
||||
|
||||
crate use base::{Primitive, ShellObject, Value};
|
||||
crate use desc::{DataDescriptor, DataDescriptorInstance};
|
||||
crate use dict::Dictionary;
|
||||
crate use files::DirEntry;
|
134
src/object/base.rs
Normal file
134
src/object/base.rs
Normal file
@ -0,0 +1,134 @@
|
||||
use crate::format::{EntriesView, GenericView};
|
||||
use crate::object::desc::DataDescriptor;
|
||||
use chrono::NaiveDateTime;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Primitive {
|
||||
Nothing,
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
String(String),
|
||||
Boolean(bool),
|
||||
Date(NaiveDateTime),
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
crate fn format(&self) -> String {
|
||||
match self {
|
||||
Primitive::Nothing => format!("Nothing"),
|
||||
Primitive::Int(i) => format!("{}", i),
|
||||
Primitive::Float(f) => format!("{}", f),
|
||||
Primitive::String(s) => format!("{:?}", s),
|
||||
Primitive::Boolean(b) => format!("{:?}", b),
|
||||
Primitive::Date(d) => format!("{}", d),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
Primitive(Primitive),
|
||||
Object(Box<dyn ShellObject>),
|
||||
List(Vec<Value>),
|
||||
}
|
||||
|
||||
impl ShellObject for Value {
|
||||
fn to_shell_string(&self) -> String {
|
||||
match self {
|
||||
Value::Primitive(p) => p.format(),
|
||||
Value::Object(o) => o.to_shell_string(),
|
||||
Value::List(l) => format!("[list List]"),
|
||||
}
|
||||
}
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||
match self {
|
||||
Value::Primitive(p) => vec![],
|
||||
Value::Object(o) => o.data_descriptors(),
|
||||
Value::List(l) => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value> {
|
||||
match self {
|
||||
Value::Primitive(p) => crate::MaybeOwned::Owned(Value::nothing()),
|
||||
Value::Object(o) => o.get_data(desc),
|
||||
Value::List(l) => crate::MaybeOwned::Owned(Value::nothing()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
crate fn format_leaf(&self) -> String {
|
||||
match self {
|
||||
Value::Primitive(p) => p.format(),
|
||||
Value::Object(o) => format!("[object Object]"),
|
||||
Value::List(l) => format!("[list List]"),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn string(s: impl Into<String>) -> Value {
|
||||
Value::Primitive(Primitive::String(s.into()))
|
||||
}
|
||||
|
||||
crate fn int(s: impl Into<i64>) -> Value {
|
||||
Value::Primitive(Primitive::Int(s.into()))
|
||||
}
|
||||
|
||||
crate fn boolean(s: impl Into<bool>) -> Value {
|
||||
Value::Primitive(Primitive::Boolean(s.into()))
|
||||
}
|
||||
|
||||
crate fn nothing() -> Value {
|
||||
Value::Primitive(Primitive::Nothing)
|
||||
}
|
||||
|
||||
crate fn list(values: impl Into<Vec<Value>>) -> Value {
|
||||
Value::List(values.into())
|
||||
}
|
||||
|
||||
crate fn object(value: impl ShellObject + 'static) -> Value {
|
||||
Value::Object(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ShellObject: Debug {
|
||||
fn to_shell_string(&self) -> String;
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor>;
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value>;
|
||||
}
|
||||
|
||||
pub trait ToEntriesView {
|
||||
fn to_entries_view(&self) -> EntriesView;
|
||||
}
|
||||
|
||||
impl ToEntriesView for ShellObject {
|
||||
fn to_entries_view(&self) -> EntriesView {
|
||||
let descs = self.data_descriptors();
|
||||
let mut entries = vec![];
|
||||
|
||||
for desc in descs {
|
||||
let value = self.get_data(&desc);
|
||||
|
||||
let formatted_value = match value.borrow() {
|
||||
Value::Primitive(p) => p.format(),
|
||||
Value::Object(o) => format!("[object Object]"),
|
||||
Value::List(l) => format!("[object List]"),
|
||||
};
|
||||
|
||||
entries.push((desc.name.clone(), formatted_value))
|
||||
}
|
||||
|
||||
EntriesView::new(entries)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToGenericView {
|
||||
fn to_generic_view(&self) -> GenericView;
|
||||
}
|
||||
|
||||
impl ToGenericView for Value {
|
||||
fn to_generic_view(&self) -> GenericView<'_> {
|
||||
GenericView::new(self)
|
||||
}
|
||||
}
|
25
src/object/desc.rs
Normal file
25
src/object/desc.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use crate::object::types::{Any, Type};
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DataDescriptor {
|
||||
crate name: String,
|
||||
crate readonly: bool,
|
||||
crate ty: Box<dyn Type>,
|
||||
}
|
||||
|
||||
impl DataDescriptor {
|
||||
crate fn any(name: impl Into<String>) -> DataDescriptor {
|
||||
DataDescriptor {
|
||||
name: name.into(),
|
||||
readonly: true,
|
||||
ty: Box::new(Any),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DataDescriptorInstance<'desc> {
|
||||
desc: &'desc DataDescriptor,
|
||||
value: crate::object::base::Value,
|
||||
}
|
73
src/object/dict.rs
Normal file
73
src/object/dict.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use crate::object::desc::DataDescriptor;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::MaybeOwned;
|
||||
use derive_new::new;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Dictionary {
|
||||
entries: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Dictionary {
|
||||
crate fn add(&mut self, name: impl Into<String>, value: Value) {
|
||||
self.entries.insert(name.into(), value);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::object::ShellObject for Dictionary {
|
||||
fn to_shell_string(&self) -> String {
|
||||
format!("[object Object] lol")
|
||||
}
|
||||
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|(name, value)| {
|
||||
DataDescriptor::new(name.clone(), true, Box::new(crate::object::types::Any))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
||||
match self.entries.get(&desc.name) {
|
||||
Some(v) => MaybeOwned::Borrowed(v),
|
||||
None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ScopedDictionary<'parent> {
|
||||
entries: BTreeMap<String, MaybeOwned<'parent, Value>>,
|
||||
}
|
||||
|
||||
impl ScopedDictionary<'parent> {
|
||||
crate fn add(&mut self, name: impl Into<String>, value: impl Into<MaybeOwned<'parent, Value>>) {
|
||||
self.entries.insert(name.into(), value.into());
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::object::ShellObject for ScopedDictionary<'parent> {
|
||||
fn to_shell_string(&self) -> String {
|
||||
format!("[object Object] lol")
|
||||
}
|
||||
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|(name, value)| {
|
||||
DataDescriptor::new(name.clone(), true, Box::new(crate::object::types::Any))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
||||
match self.entries.get(&desc.name) {
|
||||
Some(v) => MaybeOwned::Borrowed(v.borrow()),
|
||||
None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)),
|
||||
}
|
||||
}
|
||||
}
|
57
src/object/files.rs
Normal file
57
src/object/files.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{DataDescriptor, Dictionary, ShellObject, Value};
|
||||
use crate::MaybeOwned;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirEntry {
|
||||
inner: std::fs::DirEntry,
|
||||
dict: Dictionary,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FileType {
|
||||
Dir,
|
||||
File,
|
||||
Symlink,
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
crate fn new(inner: std::fs::DirEntry) -> Result<DirEntry, ShellError> {
|
||||
let mut dict = Dictionary::default();
|
||||
let filename = inner.file_name();
|
||||
dict.add("file_name", Value::string(filename.to_string_lossy()));
|
||||
|
||||
let metadata = inner.metadata()?;
|
||||
// let file_type = inner.file_type()?;
|
||||
|
||||
let kind = if metadata.is_dir() {
|
||||
FileType::Dir
|
||||
} else if metadata.is_file() {
|
||||
FileType::File
|
||||
} else {
|
||||
FileType::Symlink
|
||||
};
|
||||
|
||||
dict.add("file_type", Value::string(format!("{:?}", kind)));
|
||||
dict.add(
|
||||
"readonly",
|
||||
Value::boolean(metadata.permissions().readonly()),
|
||||
);
|
||||
|
||||
Ok(DirEntry { inner, dict })
|
||||
}
|
||||
}
|
||||
|
||||
impl ShellObject for DirEntry {
|
||||
fn to_shell_string(&self) -> String {
|
||||
format!("[object DirEntry]")
|
||||
}
|
||||
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||
self.dict.data_descriptors()
|
||||
}
|
||||
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
||||
self.dict.get_data(desc)
|
||||
}
|
||||
}
|
0
src/object/operators.rs
Normal file
0
src/object/operators.rs
Normal file
48
src/object/process.rs
Normal file
48
src/object/process.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::object::base::{Primitive, ShellObject, Value};
|
||||
use crate::object::desc::DataDescriptor;
|
||||
use crate::object::dict::Dictionary;
|
||||
use crate::MaybeOwned;
|
||||
use derive_new::new;
|
||||
use itertools::join;
|
||||
use sysinfo::ProcessExt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Process {
|
||||
inner: sysinfo::Process,
|
||||
dict: Dictionary,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
crate fn new(inner: sysinfo::Process) -> Process {
|
||||
let mut dict = Dictionary::default();
|
||||
dict.add("name", Value::string(inner.name()));
|
||||
|
||||
let cmd = inner.cmd();
|
||||
|
||||
let cmd_value = if cmd.len() == 0 {
|
||||
Value::nothing()
|
||||
} else {
|
||||
Value::string(join(cmd, ""))
|
||||
};
|
||||
|
||||
dict.add("cmd", cmd_value);
|
||||
dict.add("pid", Value::int(inner.pid() as i64));
|
||||
dict.add("status", Value::int(inner.status() as i64));
|
||||
|
||||
Process { inner, dict }
|
||||
}
|
||||
}
|
||||
|
||||
impl ShellObject for Process {
|
||||
fn to_shell_string(&self) -> String {
|
||||
format!("{} - {}", self.inner.name(), self.inner.pid())
|
||||
}
|
||||
|
||||
fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||
self.dict.data_descriptors()
|
||||
}
|
||||
|
||||
fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> {
|
||||
self.dict.get_data(desc)
|
||||
}
|
||||
}
|
5
src/object/types.rs
Normal file
5
src/object/types.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub trait Type {}
|
||||
|
||||
pub struct Any;
|
||||
|
||||
impl Type for Any {}
|
Reference in New Issue
Block a user