Manos Pitsidianakis 2 weeks ago
parent 11a0586d56
commit b2a6e15e76
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

923
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -39,6 +39,7 @@ serde_json = "1.0"
signal-hook = { version = "^0.3", default-features = false, features = ["iterator"] }
signal-hook-registry = { version = "1.2.0", default-features = false }
smallvec = { version = "^1.5.0", features = ["serde"] }
starlark = { version = "0.12.0", optional = true }
structopt = { version = "0.3.14", default-features = false }
svg_crate = { version = "^0.13", optional = true, package = "svg" }
termion = { version = "1.5.1", default-features = false }
@ -52,7 +53,7 @@ version = "0.2.3"
optional = true
[features]
default = ["sqlite3", "notmuch", "smtp", "dbus-notifications", "gpgme", "cli-docs", "jmap", "static"]
default = ["sqlite3", "notmuch", "smtp", "dbus-notifications", "gpgme", "cli-docs", "jmap", "static", "plugins"]
notmuch = ["melib/notmuch"]
jmap = ["melib/jmap"]
sqlite3 = ["melib/sqlite3"]
@ -69,6 +70,7 @@ http-static = ["melib/http-static"]
sqlite3-static = ["melib/sqlite3-static"]
dbus-static = ["dep:notify-rust", "notify-rust?/d_vendored"]
libz-static = ["dep:libz-sys", "libz-sys?/static"]
plugins = ["dep:starlark"]
static = ["tls-static", "http-static", "sqlite3-static", "dbus-static", "libz-static"]
# Print tracing logs as meli runs in stderr

@ -139,6 +139,9 @@ pub mod notifications;
pub mod mailbox_management;
pub use mailbox_management::*;
#[cfg(feature = "plugins")]
pub mod plugins;
pub mod jobs_view;
pub use jobs_view::*;

@ -19,6 +19,11 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
//! Plugins.
mod starlark;
/*
//! Plugins are executed by meli and communication is done by `messagepack` IPC.
use melib::error::{Error, Result};
@ -301,3 +306,4 @@ pub enum FilterResult {
Binary(Vec<u8>),
Error(String),
}
*/

@ -0,0 +1,411 @@
/*
* ____
*
* Copyright ____ Manos Pitsidianakis
*
* This file is part of ____.
*
* ____ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ____ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ____. If not, see <http://www.gnu.org/licenses/>.
*/
#[cfg(test)]
#[test]
fn test_starlark() {
use starlark::{
environment::{Globals, Module},
eval::Evaluator,
syntax::{AstModule, Dialect},
values::Value,
};
let content = r#"
def hello():
return "hello"
hello() + " world!"
"#;
// We first parse the content, giving a filename and the Starlark
// `Dialect` we'd like to use (we pick standard).
let ast: AstModule =
AstModule::parse("hello_world.star", content.to_owned(), &Dialect::Standard).unwrap();
// We create a `Globals`, defining the standard library functions available.
// The `standard` function uses those defined in the Starlark specification.
let globals: Globals = Globals::standard();
// We create a `Module`, which stores the global variables for our calculation.
let module: Module = Module::new();
// We create an evaluator, which controls how evaluation occurs.
let mut eval: Evaluator = Evaluator::new(&module);
// And finally we evaluate the code using the evaluator.
let res: Value = eval.eval_module(ast, &globals).unwrap();
assert_eq!(res.unpack_str(), Some("hello world!"));
}
#[cfg(test)]
#[test]
fn test_starlark_2() {
use starlark::{
environment::{GlobalsBuilder, Module},
eval::Evaluator,
starlark_module,
syntax::{AstModule, Dialect},
};
// This defines the function that is visible to Starlark
#[starlark_module]
fn starlark_quadratic(builder: &mut GlobalsBuilder) {
fn quadratic(a: i32, b: i32, c: i32, x: i32) -> starlark::Result<i32> {
Ok(a * x * x + b * x + c)
}
}
// We build our globals to make the function available in Starlark
let globals = GlobalsBuilder::new().with(starlark_quadratic).build();
let module = Module::new();
let mut eval = Evaluator::new(&module);
// Let's test calling the function from Starlark code
let starlark_code = r#"
quadratic(4, 2, 1, x = 8)
"#;
let ast = AstModule::parse(
"quadratic.star",
starlark_code.to_owned(),
&Dialect::Standard,
)
.unwrap();
let res = eval.eval_module(ast, &globals).unwrap();
assert_eq!(res.unpack_i32(), Some(273)); // Verify that we got an `int`
// return value of 4 * 8^2 + 2 * 8
// + 1 = 273
}
#[cfg(test)]
#[test]
fn test_starlark_3() {
use std::cell::RefCell;
use starlark::{
any::ProvidesStaticType,
environment::{GlobalsBuilder, Module},
eval::Evaluator,
starlark_module,
syntax::{AstModule, Dialect},
values::{none::NoneType, Value},
};
let content = r#"
emit(1)
emit(["test"])
emit({"x": "y"})
"#;
// Define a store in which to accumulate JSON strings
#[derive(Debug, ProvidesStaticType, Default)]
struct Store(RefCell<Vec<String>>);
impl Store {
fn add(&self, x: String) {
self.0.borrow_mut().push(x)
}
}
#[starlark_module]
fn starlark_emit(builder: &mut GlobalsBuilder) {
fn emit(x: Value, eval: &mut Evaluator) -> starlark::Result<NoneType> {
// We modify extra (which we know is a Store) and add the JSON of the
// value the user gave.
eval.extra
.unwrap()
.downcast_ref::<Store>()
.unwrap()
.add(x.to_json()?);
Ok(NoneType)
}
}
let ast = AstModule::parse("json.star", content.to_owned(), &Dialect::Standard).unwrap();
// We build our globals adding some functions we wrote
let globals = GlobalsBuilder::new().with(starlark_emit).build();
let module = Module::new();
let store = Store::default();
{
let mut eval = Evaluator::new(&module);
// We add a reference to our store
eval.extra = Some(&store);
eval.eval_module(ast, &globals).unwrap();
}
assert_eq!(&*store.0.borrow(), &["1", "[\"test\"]", "{\"x\":\"y\"}"]);
}
#[cfg(test)]
#[test]
fn test_starlark_4() {
use starlark::{
environment::{Globals, Module},
eval::Evaluator,
syntax::{AstModule, Dialect, DialectTypes},
};
let content = r#"
def takes_int(x: int):
pass
takes_int("test")
"#;
// Make the dialect enable types
let dialect = Dialect {
enable_types: DialectTypes::Enable,
..Dialect::Standard
};
// We could equally have done `dialect = Dialect::Extended`.
let ast = AstModule::parse("json.star", content.to_owned(), &dialect).unwrap();
let globals = Globals::standard();
let module = Module::new();
let mut eval = Evaluator::new(&module);
let res = eval.eval_module(ast, &globals);
// We expect this to fail, since it is a type violation
assert!(res
.unwrap_err()
.to_string()
.contains("Value `test` of type `string` does not match the type annotation `int`"));
}
#[cfg(test)]
#[test]
fn test_starlark_5() {
use starlark::{
environment::{FrozenModule, Globals, Module},
eval::{Evaluator, ReturnFileLoader},
syntax::{AstModule, Dialect},
};
// Get the file contents (for the demo), in reality use `AstModule::parse_file`.
fn get_source(file: &str) -> &str {
match file {
"a.star" => "a = 7",
"b.star" => "b = 6",
_ => {
r#"
load('a.star', 'a')
load('b.star', 'b')
ab = a * b
"#
}
}
}
fn get_module(file: &str) -> starlark::Result<FrozenModule> {
let ast = AstModule::parse(file, get_source(file).to_owned(), &Dialect::Standard)?;
// We can get the loaded modules from `ast.loads`.
// And ultimately produce a `loader` capable of giving those modules to
// Starlark.
let mut loads = Vec::new();
for load in ast.loads() {
loads.push((load.module_id.to_owned(), get_module(load.module_id)?));
}
let modules = loads.iter().map(|(a, b)| (a.as_str(), b)).collect();
let mut loader = ReturnFileLoader { modules: &modules };
let globals = Globals::standard();
let module = Module::new();
{
let mut eval = Evaluator::new(&module);
eval.set_loader(&mut loader);
eval.eval_module(ast, &globals)?;
}
// After creating a module we freeze it, preventing further mutation.
// It can now be used as the input for other Starlark modules.
Ok(module.freeze()?)
}
let ab = get_module("ab.star").unwrap();
assert_eq!(ab.get("ab").unwrap().unpack_i32(), Some(42));
}
#[cfg(test)]
#[test]
fn test_starlark_6() {
use starlark::{
environment::{Globals, Module},
eval::Evaluator,
syntax::{AstModule, Dialect},
};
let content = r#"
def quadratic(a, b, c, x):
return a*x*x + b*x + c
quadratic
"#;
let ast = AstModule::parse("quadratic.star", content.to_owned(), &Dialect::Extended).unwrap();
let globals = Globals::standard();
let module = Module::new();
let mut eval = Evaluator::new(&module);
let quad = eval.eval_module(ast, &globals).unwrap();
let heap = module.heap();
let res = eval
.eval_function(
quad,
&[heap.alloc(4), heap.alloc(2), heap.alloc(1)],
&[("x", heap.alloc(8))],
)
.unwrap();
assert_eq!(res.unpack_i32(), Some(273));
}
#[cfg(test)]
#[test]
fn test_starlark_datetime_fmt() {
use starlark::{
environment::{GlobalsBuilder, Module},
eval::Evaluator,
starlark_module,
syntax::{AstModule, Dialect},
values::Value,
};
let content = r#"
def datetime_fmt():
now_val = now()
print("now returned ", now_val)
n = since(now_val)
print("since returned ", n)
if n < 60 * 60:
return "{} minute{} ago".format((n / (60)), ("" if n / 60 == 1 else "s"))
elif n < 24 * 60 * 60:
return "{} hour{} ago".format( n / (60 * 60), "" if n / (60 * 60) == 1 else "s")
elif n < 7 * 24 * 60 * 60:
return "{} day{} ago".format( n / (24 * 60 * 60), "" if n / (24 * 60 * 60) == 1 else "s")
else:
return "{}".format(n)
datetime_fmt
"#;
// This defines the function that is visible to Starlark
#[starlark_module]
fn starlark_datetime_fmt(builder: &mut GlobalsBuilder) {
fn print(s: Value, val: u64) -> starlark::Result<i32> {
let ss: &str = s.unpack_str().unwrap_or("");
println!("{ss}{val}");
Ok(1)
}
fn now() -> starlark::Result<u64> {
let d = std::time::UNIX_EPOCH;
let now: std::time::Duration = std::time::SystemTime::now().duration_since(d).unwrap();
Ok(now.as_secs())
}
fn since(epoch: u64) -> starlark::Result<u64> {
let d = std::time::UNIX_EPOCH + std::time::Duration::from_secs(epoch);
let now: std::time::Duration = std::time::SystemTime::now()
.duration_since(d)
.unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
Ok(now.as_secs())
}
}
let ast =
AstModule::parse("datetime_fmt.star", content.to_owned(), &Dialect::Extended).unwrap();
let globals = GlobalsBuilder::new().with(starlark_datetime_fmt).build();
let module = Module::new();
let mut eval = Evaluator::new(&module);
let quad = eval.eval_module(ast, &globals).unwrap();
let res = eval.eval_function(quad, &[], &[]).unwrap();
assert_eq!(
res.unpack_str(),
Some("0.0 minutes ago".to_string()).as_deref()
);
}
#[cfg(test)]
#[test]
fn test_starlark_7() {
/*
use starlark::starlark_module;
use std::fmt::Display;
use std::fmt::Write;
use std::fmt::{self};
use allocative::Allocative;
use starlark::environment::Globals;
use starlark::environment::Module;
use starlark::eval::Evaluator;
use starlark::starlark_simple_value;
use starlark::syntax::AstModule;
use starlark::syntax::Dialect;
use starlark::values::Heap;
use starlark::values::NoSerialize;
use starlark::values::ProvidesStaticType;
use starlark::values::StarlarkValue;
use starlark::values::Value;
use starlark::values::ValueError;
use starlark::values::ValueLike;
use starlark_derive::starlark_value;
// Define complex numbers
#[derive(Debug, PartialEq, Eq, ProvidesStaticType, NoSerialize, Allocative)]
struct Complex {
real: i32,
imaginary: i32,
}
starlark_simple_value!(Complex);
impl Display for Complex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} + {}i", self.real, self.imaginary)
}
}
#[starlark_value(type = "complex")]
impl<'v> StarlarkValue<'v> for Complex {
// How we add them
fn add(&self, rhs: Value<'v>, heap: &'v Heap) -> Option<starlark::Result<Value<'v>>> {
if let Some(rhs) = rhs.downcast_ref::<Self>() {
Some(Ok(heap.alloc(Complex {
real: self.real + rhs.real,
imaginary: self.imaginary + rhs.imaginary,
})))
} else {
None
}
}
}
let content = "str(a + b)";
let ast = AstModule::parse("complex.star", content.to_owned(), &Dialect::Standard).unwrap();
let globals = Globals::standard();
let module = Module::new();
// We inject some complex numbers into the module before we start.
let a = module.heap().alloc(Complex {
real: 1,
imaginary: 8,
});
module.set("a", a);
let b = module.heap().alloc(Complex {
real: 4,
imaginary: 2,
});
module.set("b", b);
let mut eval = Evaluator::new(&module);
let res = eval.eval_module(ast, &globals).unwrap();
assert_eq!(res.unpack_str(), Some("5 + 10i"));
*/
}
Loading…
Cancel
Save