Fix clippy warnings & errors

This commit is contained in:
NGnius (Graham) 2022-07-30 00:05:03 -04:00
parent 2bec331700
commit 2b6c47f166
52 changed files with 305 additions and 304 deletions

View file

@ -1,4 +1,4 @@
use mps_interpreter::MpsFaye;
use muss_interpreter::Interpreter;
//use mps_interpreter::MpsRunner;
use std::fs::File;
use std::io::{BufReader, Read, Seek};
@ -35,12 +35,12 @@ fn faye_benchmark(c: &mut Criterion) {
let mut buf = Vec::with_capacity(1024 * 1024);
reader.read_to_end(&mut buf).unwrap();
drop(buf);
c.bench_function("mps-faye lots_of_empty.mps", |b| {
c.bench_function("muss-faye lots_of_empty.mps", |b| {
b.iter(|| {
//let f = File::open("benches/lots_of_empty.mps").unwrap();
//let mut reader = BufReader::new(f);
reader.rewind().unwrap();
let mps = MpsFaye::with_stream(&mut reader);
let mps = Interpreter::with_stream(&mut reader);
for item in mps {
match item {
Err(e) => panic!("{}", e),

View file

@ -83,7 +83,7 @@ dependencies = [
[[package]]
name = "bliss-audio-symphonia"
version = "0.4.6"
version = "0.5.0"
dependencies = [
"bliss-audio-aubio-rs",
"crossbeam",
@ -96,6 +96,7 @@ dependencies = [
"noisy_float",
"num_cpus",
"rayon",
"rcue",
"ripemd160",
"rustfft",
"strum",
@ -567,7 +568,7 @@ dependencies = [
[[package]]
name = "muss-interpreter"
version = "0.8.0"
version = "0.9.0"
dependencies = [
"bliss-audio-symphonia",
"dirs",
@ -871,6 +872,12 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "rcue"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca1481d62f18158646de2ec552dd63f8bdc5be6448389b192ba95c939df997e"
[[package]]
name = "redox_syscall"
version = "0.2.13"

View file

@ -48,7 +48,6 @@ where
fn next(&mut self) -> Option<Self::Item> {
let next_item = self.interpreter.next();
let transmuted_next = (self.transmuter)(&mut self.interpreter, next_item);
transmuted_next
(self.transmuter)(&mut self.interpreter, next_item)
}
}

View file

@ -29,8 +29,8 @@ where
}
#[inline]
fn empty_callback<'a, T: TokenReader>(
_s: &mut Interpreter<'a, T>,
fn empty_callback<T: TokenReader>(
_s: &mut Interpreter<'_, T>,
_d: InterpreterEvent,
) -> Result<(), InterpreterError> {
Ok(())

View file

@ -23,26 +23,26 @@ pub(crate) fn standard_vocab(vocabulary: &mut LanguageDictionary) {
// iter blocks
.add(
crate::lang::ItemBlockFactory::new()
.add(crate::lang::vocabulary::item_ops::ConstantItemOpFactory)
.add(crate::lang::vocabulary::item_ops::VariableAssignItemOpFactory)
.add(crate::lang::vocabulary::item_ops::FieldAssignItemOpFactory)
.add(crate::lang::vocabulary::item_ops::FileItemOpFactory)
.add(crate::lang::vocabulary::item_ops::VariableDeclareItemOpFactory)
.add(crate::lang::vocabulary::item_ops::InterpolateStringItemOpFactory)
.add(crate::lang::vocabulary::item_ops::BranchItemOpFactory)
.add(crate::lang::vocabulary::item_ops::IterItemOpFactory)
.add(crate::lang::vocabulary::item_ops::ConstructorItemOpFactory)
.add(crate::lang::vocabulary::item_ops::EmptyItemOpFactory)
.add(crate::lang::vocabulary::item_ops::RemoveItemOpFactory)
.add(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory)
.add(crate::lang::vocabulary::item_ops::NegateItemOpFactory)
.add(crate::lang::vocabulary::item_ops::NotItemOpFactory)
.add(crate::lang::vocabulary::item_ops::CompareItemOpFactory)
.add(crate::lang::vocabulary::item_ops::AddItemOpFactory)
.add(crate::lang::vocabulary::item_ops::SubtractItemOpFactory)
.add(crate::lang::vocabulary::item_ops::OrItemOpFactory)
.add(crate::lang::vocabulary::item_ops::AndItemOpFactory)
.add(crate::lang::vocabulary::item_ops::BracketsItemOpFactory),
.push(crate::lang::vocabulary::item_ops::ConstantItemOpFactory)
.push(crate::lang::vocabulary::item_ops::VariableAssignItemOpFactory)
.push(crate::lang::vocabulary::item_ops::FieldAssignItemOpFactory)
.push(crate::lang::vocabulary::item_ops::FileItemOpFactory)
.push(crate::lang::vocabulary::item_ops::VariableDeclareItemOpFactory)
.push(crate::lang::vocabulary::item_ops::InterpolateStringItemOpFactory)
.push(crate::lang::vocabulary::item_ops::BranchItemOpFactory)
.push(crate::lang::vocabulary::item_ops::IterItemOpFactory)
.push(crate::lang::vocabulary::item_ops::ConstructorItemOpFactory)
.push(crate::lang::vocabulary::item_ops::EmptyItemOpFactory)
.push(crate::lang::vocabulary::item_ops::RemoveItemOpFactory)
.push(crate::lang::vocabulary::item_ops::VariableRetrieveItemOpFactory)
.push(crate::lang::vocabulary::item_ops::NegateItemOpFactory)
.push(crate::lang::vocabulary::item_ops::NotItemOpFactory)
.push(crate::lang::vocabulary::item_ops::CompareItemOpFactory)
.push(crate::lang::vocabulary::item_ops::AddItemOpFactory)
.push(crate::lang::vocabulary::item_ops::SubtractItemOpFactory)
.push(crate::lang::vocabulary::item_ops::OrItemOpFactory)
.push(crate::lang::vocabulary::item_ops::AndItemOpFactory)
.push(crate::lang::vocabulary::item_ops::BracketsItemOpFactory),
)
// functions and misc
// functions don't enforce bracket coherence

View file

@ -45,6 +45,10 @@ impl Item {
pub fn len(&self) -> usize {
self.fields.len()
}
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
impl Display for Item {

View file

@ -53,6 +53,7 @@ impl LanguageDictionary {
}
}
#[allow(clippy::derivable_impls)]
impl Default for LanguageDictionary {
fn default() -> Self {
Self {

View file

@ -227,7 +227,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
let matches_result = self.predicate.matches(&item, &mut ctx);
let matches = match matches_result {
Err(e) => {
maybe_result = Some(Err(e.with(RuntimeOp(fake.clone()))));
maybe_result = Some(Err(e.with(RuntimeOp(fake))));
self.context = Some(ctx);
break;
}
@ -245,7 +245,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
Err(e) => {
//self.context = Some(op.escape());
maybe_result =
Some(Err(e.with(RuntimeOp(fake.clone()))));
Some(Err(e.with(RuntimeOp(fake))));
self.context = Some(ctx);
break;
}
@ -269,7 +269,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
Err(e) => match maybe_result {
Some(Ok(_)) => {
maybe_result = Some(Err(
e.with(RuntimeOp(fake.clone()))
e.with(RuntimeOp(fake))
))
}
Some(Err(e2)) => maybe_result = Some(Err(e2)), // already failing, do not replace error,
@ -286,7 +286,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
Err(e) => {
//self.context = Some(op.escape());
maybe_result =
Some(Err(e.with(RuntimeOp(fake.clone()))));
Some(Err(e.with(RuntimeOp(fake))));
self.context = Some(ctx);
break;
}
@ -332,7 +332,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
}
Err(e) => {
self.is_failing = true; // this is unrecoverable and reproducible, so it shouldn't be tried again (to prevent error spam)
return Some(Err(e.with(RuntimeOp(fake.clone()))))
return Some(Err(e.with(RuntimeOp(fake))))
},
};
let mut maybe_result = None;
@ -434,7 +434,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterStatement<P> {
.variables
.declare(variable_name, Type::Op(variable))
{
Err(e) => Some(Err(e.with(RuntimeOp(fake.clone())))),
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
Ok(_) => maybe_result,
}
}
@ -479,6 +479,7 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static>
impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
for FilterStatementFactory<P, F>
{
#[allow(clippy::unnecessary_unwrap)]
fn is_op_boxed(&self, tokens: &VecDeque<Token>) -> bool {
let tokens_len = tokens.len();
if is_correct_format(tokens) {
@ -524,8 +525,7 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
dict: &LanguageDictionary,
) -> Result<Box<dyn Op>, SyntaxError> {
let start_of_op = last_dot_before_open_bracket(tokens);
let op;
if start_of_op == 1 && tokens[0].is_name() {
let op = if start_of_op == 1 && tokens[0].is_name() {
// variable_name.(predicate)
let variable_name = assert_token(
|t| match t {
@ -535,15 +535,15 @@ impl<P: FilterPredicate + 'static, F: FilterFactory<P> + 'static> BoxedOpFactory
Token::Name("variable_name".into()),
tokens,
)?;
op = VariableOrOp::Variable(variable_name);
VariableOrOp::Variable(variable_name)
} else {
// <some other op>.(predicate)
//let mut new_tokens = tokens.range(0..start_of_op).map(|x| x.to_owned()).collect();
let end_tokens = tokens.split_off(start_of_op); // don't parse filter in inner statement
let inner_op = dict.try_build_statement(tokens)?;
tokens.extend(end_tokens);
op = VariableOrOp::Op(inner_op.into());
}
VariableOrOp::Op(inner_op.into())
};
assert_token_raw(Token::Dot, tokens)?;
assert_token_raw(Token::OpenBracket, tokens)?;
if !tokens.is_empty() && check_name("if", &tokens[0]) {

View file

@ -190,7 +190,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
Ok(x) => {
return Some(Err(RuntimeError {
line: 0,
op: fake.clone(),
op: fake,
msg: format!(
"Expected operation/iterable type in variable {}, got {}",
&variable_name, x
@ -203,15 +203,14 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
variable.enter(ctx);
let item = variable.next();
self.context = Some(variable.escape());
match self
if let Err(e) = self
.context
.as_mut()
.unwrap()
.variables
.declare(variable_name, Type::Op(variable))
{
Err(e) => return Some(Err(e.with(RuntimeOp(fake)))),
Ok(_) => {}
return Some(Err(e.with(RuntimeOp(fake))));
}
item
}
@ -242,9 +241,8 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
// invoke inner op
real_op.enter(self.context.take().unwrap());
if real_op.is_resetable() {
match real_op.reset() {
Err(e) => return Some(Err(e)),
Ok(_) => {}
if let Err(e) = real_op.reset() {
return Some(Err(e));
}
}
for item in real_op.by_ref() {
@ -287,9 +285,8 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
// invoke inner operation
real_op.enter(self.context.take().unwrap());
if real_op.is_resetable() {
match real_op.reset() {
Err(e) => return Some(Err(e)),
Ok(_) => {}
if let Err(e) = real_op.reset() {
return Some(Err(e));
}
}
for item in real_op.by_ref() {
@ -319,7 +316,7 @@ impl<P: FilterPredicate + 'static> Iterator for FilterReplaceStatement<P> {
Some(Ok(item))
}
}
Err(e) => Some(Err(e.with(RuntimeOp(fake.clone())))),
Err(e) => Some(Err(e.with(RuntimeOp(fake)))),
}
}
Some(Err(e)) => Some(Err(e)),
@ -347,12 +344,11 @@ fn declare_or_replace_item(
single: SingleItem,
ctx: &mut Context,
) -> Result<Option<Type>, RuntimeMsg> {
let old_item: Option<Type>;
if ctx.variables.exists(ITEM_VARIABLE_NAME) {
old_item = Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?);
let old_item: Option<Type> = if ctx.variables.exists(ITEM_VARIABLE_NAME) {
Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?)
} else {
old_item = None;
}
None
};
ctx.variables
.declare(ITEM_VARIABLE_NAME, Type::Op(Box::new(single)))?;
Ok(old_item)

View file

@ -1,3 +1,4 @@
#![allow(clippy::new_without_default)]
use core::ops::Deref;
use std::collections::VecDeque;
use std::fmt::{Debug, Display, Error, Formatter};
@ -67,11 +68,11 @@ pub struct ItemBlockStatement {
impl Display for ItemBlockStatement {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}.{{", self.iterable)?;
if self.statements.len() > 0 {
write!(f, "\n")?;
if !self.statements.is_empty() {
writeln!(f)?;
}
for statement in self.statements.iter() {
write!(f, "{}\n", statement)?;
writeln!(f, "{}", statement)?;
}
write!(f, "}}")
}
@ -213,7 +214,7 @@ pub struct ItemBlockFactory {
}
impl ItemBlockFactory {
pub fn add<
pub fn push<
T: ItemOpFactory<Y> + 'static,
Y: Deref<Target = dyn ItemOp> + ItemOp + 'static,
>(
@ -317,12 +318,11 @@ fn restore_item_var(
ctx: &mut Context,
old_var: Option<Type>,
) -> Result<Option<Type>, RuntimeMsg> {
let new_var;
if ctx.variables.exists(ITEM_VARIABLE_NAME) {
new_var = Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?);
let new_var = if ctx.variables.exists(ITEM_VARIABLE_NAME) {
Some(ctx.variables.remove(ITEM_VARIABLE_NAME)?)
} else {
new_var = None;
}
None
};
if let Some(old_var) = old_var {
ctx.variables.declare(ITEM_VARIABLE_NAME, old_var)?;
}

View file

@ -1,3 +1,5 @@
#![allow(clippy::match_like_matches_macro)]
#![allow(clippy::needless_range_loop)]
mod db_items;
mod dictionary;
mod error;

View file

@ -1,3 +1,4 @@
#![allow(clippy::borrowed_box)]
use std::fmt::{Debug, Display, Error, Formatter};
use super::Op;

View file

@ -13,7 +13,7 @@ use crate::Context;
const SORTER_ITEM_CACHE_SIZE: usize = 8;
pub trait Sorter: Clone + Debug + Display {
fn sort<'a>(
fn sort(
&mut self,
iterator: &mut dyn Op,
item_buf: &mut VecDeque<IteratorItem>,

View file

@ -19,7 +19,7 @@ impl Display for NonEmptyFilter {
impl FilterPredicate for NonEmptyFilter {
fn matches(&mut self, item: &Item, _ctx: &mut Context) -> Result<bool, RuntimeMsg> {
if item.len() != 0 {
if !item.is_empty() {
if item.len() == 1 && item.field("filename").is_some() {
Ok(false) // ignore filename field, since that almost always exists
} else {

View file

@ -90,7 +90,7 @@ pub struct UniqueFilterFactory;
impl FilterFactory<UniqueFieldFilter> for UniqueFilterFactory {
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
tokens.len() >= 2 && check_name("unique", &tokens[0])
tokens.len() >= 2 && check_name("unique", tokens[0])
}
fn build_filter(
@ -128,7 +128,7 @@ impl FilterFactory<UniqueFieldFilter> for UniqueFilterFactory {
impl FilterFactory<UniqueFilter> for UniqueFilterFactory {
fn is_filter(&self, tokens: &VecDeque<&Token>) -> bool {
tokens.len() == 1 && check_name("unique", &tokens[0])
tokens.len() == 1 && check_name("unique", tokens[0])
}
fn build_filter(

View file

@ -49,7 +49,7 @@ impl Iterator for IntersectionStatement {
type Item = IteratorItem;
fn next(&mut self) -> Option<Self::Item> {
if self.ops.len() == 0 {
if self.ops.is_empty() {
return None;
} else if self.init_needed {
self.init_needed = false;

View file

@ -36,7 +36,7 @@ impl ItemOp for AddItemOp {
let rhs = self.rhs.execute(context)?;
if let Type::Primitive(rhs) = &rhs {
Ok(Type::Primitive(
lhs.try_add(rhs).map_err(|e| RuntimeMsg(e))?,
lhs.try_add(rhs).map_err(RuntimeMsg)?,
))
} else {
Err(RuntimeMsg(format!(

View file

@ -28,29 +28,29 @@ impl Display for BranchItemOp {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "if {} {{", self.condition)?;
if self.inner_ifs.len() > 1 {
write!(f, "\n")?;
writeln!(f)?;
}
for i in 0..self.inner_ifs.len() {
write!(f, "{}", self.inner_ifs[i])?;
if i != self.inner_ifs.len() - 1 {
write!(f, ",\n")?;
writeln!(f, ",")?;
}
}
if self.inner_ifs.len() > 1 {
write!(f, "\n")?;
writeln!(f)?;
}
write!(f, "}} else {{")?;
if self.inner_elses.len() > 1 {
write!(f, "\n")?;
writeln!(f)?;
}
for i in 0..self.inner_elses.len() {
write!(f, "{}", self.inner_elses[i])?;
if i != self.inner_elses.len() - 1 {
write!(f, ",\n")?;
writeln!(f, ",")?;
}
}
if self.inner_elses.len() > 1 {
write!(f, "\n")?;
writeln!(f)?;
}
write!(f, "}}")
}

View file

@ -42,7 +42,7 @@ impl ItemOp for CompareItemOp {
let rhs_val = self.rhs.execute(context)?;
if let Type::Primitive(lhs) = lhs_val {
if let Type::Primitive(rhs) = rhs_val {
let compare = lhs.compare(&rhs).map_err(|e| RuntimeMsg(e))?;
let compare = lhs.compare(&rhs).map_err(RuntimeMsg)?;
let mut is_match = false;
for comparator in self.comparison {
if comparator == compare {

View file

@ -35,7 +35,7 @@ impl Display for ConstructorItemOp {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "Item(")?;
if self.fields.len() > 1 {
write!(f, "\n")?;
writeln!(f)?;
for i in 0..self.fields.len() - 1 {
let field = &self.fields[i];
write!(f, "{}: {}, ", field.name, field.value)?;

View file

@ -78,11 +78,10 @@ impl ItemOpFactory<FieldAssignItemOp> for FieldAssignItemOpFactory {
factory: &ItemBlockFactory,
dict: &LanguageDictionary,
) -> Result<FieldAssignItemOp, SyntaxError> {
let var_name;
if tokens[0].is_dot() {
var_name = "item".to_string();
let var_name =if tokens[0].is_dot() {
"item".to_string()
} else {
var_name = assert_token(
assert_token(
|t| match t {
Token::Name(s) => Some(s),
_ => None,
@ -90,7 +89,7 @@ impl ItemOpFactory<FieldAssignItemOp> for FieldAssignItemOpFactory {
Token::Name("variable_name".into()),
tokens,
)?
}
};
assert_token_raw(Token::Dot, tokens)?;
let f_name = assert_token(
|t| match t {

View file

@ -30,7 +30,7 @@ impl Display for IterItemOp {
impl ItemOp for IterItemOp {
fn execute(&self, _context: &mut Context) -> Result<Type, RuntimeMsg> {
Ok(Type::Op(self.inner.dup().into()))
Ok(Type::Op(self.inner.dup()))
}
}

View file

@ -33,7 +33,7 @@ impl ItemOp for NegateItemOp {
let rhs = self.rhs.execute(context)?;
if let Type::Primitive(rhs) = &rhs {
Ok(Type::Primitive(
rhs.try_negate().map_err(|e| RuntimeMsg(e))?,
rhs.try_negate().map_err(RuntimeMsg)?,
))
} else {
Err(RuntimeMsg(format!(

View file

@ -33,7 +33,7 @@ impl ItemOp for NotItemOp {
let rhs = self.rhs.execute(context)?;
if let Type::Primitive(rhs) = &rhs {
Ok(Type::Primitive(
rhs.try_not().map_err(|e| RuntimeMsg(e))?,
rhs.try_not().map_err(RuntimeMsg)?,
))
} else {
Err(RuntimeMsg(format!(

View file

@ -75,20 +75,19 @@ impl ItemOpFactory<RemoveItemOp> for RemoveItemOpFactory {
Token::Name("variable_name".into()),
tokens,
)?;
let field_opt;
if tokens.is_empty() {
field_opt = None;
let field_opt = if tokens.is_empty() {
None
} else {
assert_token_raw(Token::Dot, tokens)?;
field_opt = Some(assert_token(
Some(assert_token(
|t| match t {
Token::Name(s) => Some(s),
_ => None,
},
Token::Name("field_name".into()),
tokens,
)?);
}
)?)
};
Ok(RemoveItemOp {
variable_name: name,
field_name: field_opt,

View file

@ -86,20 +86,19 @@ impl ItemOpFactory<VariableRetrieveItemOp> for VariableRetrieveItemOpFactory {
Token::Name("variable_name".into()),
tokens,
)?;
let field_opt;
if tokens.is_empty() {
field_opt = None;
let field_opt = if tokens.is_empty() {
None
} else {
assert_token_raw(Token::Dot, tokens)?;
field_opt = Some(assert_token(
Some(assert_token(
|t| match t {
Token::Name(s) => Some(s),
_ => None,
},
Token::Name("field_name".into()),
tokens,
)?);
}
)?)
};
Ok(VariableRetrieveItemOp {
variable_name: var_name,
field_name: field_opt,

View file

@ -39,7 +39,7 @@ impl ItemOp for InterpolateStringItemOp {
}
Type::Item(item) => {
let mut result;
if item.len() == 0 {
if item.is_empty() {
result = self.format.clone();
} else {
let mut iter = item.iter();

View file

@ -36,7 +36,7 @@ impl ItemOp for SubtractItemOp {
let rhs = self.rhs.execute(context)?;
if let Type::Primitive(rhs) = &rhs {
Ok(Type::Primitive(
lhs.try_subtract(rhs).map_err(|e| RuntimeMsg(e))?,
lhs.try_subtract(rhs).map_err(RuntimeMsg)?,
))
} else {
Err(RuntimeMsg(format!(

View file

@ -40,12 +40,10 @@ impl ItemOp for VariableDeclareItemOp {
if !context.variables.exists(&self.variable_name) {
context.variables.declare(&self.variable_name, mps_type)?;
}
} else {
if !context.variables.exists(&self.variable_name) {
context
.variables
.declare(&self.variable_name, Type::empty())?;
}
} else if !context.variables.exists(&self.variable_name) {
context
.variables
.declare(&self.variable_name, Type::empty())?;
}
Ok(Type::empty())
}
@ -74,13 +72,12 @@ impl ItemOpFactory<VariableDeclareItemOp> for VariableDeclareItemOpFactory {
Token::Name("variable_name".into()),
tokens,
)?;
let inner_op: Option<Box<dyn ItemOp>>;
if !tokens.is_empty() {
let inner_op: Option<Box<dyn ItemOp>> = if !tokens.is_empty() {
assert_token_raw(Token::Equals, tokens)?;
inner_op = Some(factory.try_build_item_statement(tokens, dict)?);
Some(factory.try_build_item_statement(tokens, dict)?)
} else {
inner_op = None;
}
None
};
Ok(VariableDeclareItemOp {
variable_name: var_name,
inner: inner_op,

View file

@ -1,3 +1,4 @@
#![allow(clippy::while_let_on_iterator)]
mod empties;
pub(crate) mod empty;
mod files;

View file

@ -117,7 +117,7 @@ impl Iterator for MpdQueryStatement {
});
}
let results = self.results.as_mut().unwrap();
results.pop_front().map(|x| Ok(x))
results.pop_front().map(Ok)
}
fn size_hint(&self) -> (usize, Option<usize>) {

View file

@ -69,7 +69,7 @@ impl Iterator for RepeatStatement {
}
if real_op.is_resetable() {
while self.loop_forever || !self.inner_done {
for item in real_op.by_ref() {
if let Some(item) = real_op.next() {
return Some(item);
}
if !self.loop_forever {
@ -79,16 +79,14 @@ impl Iterator for RepeatStatement {
self.context = Some(real_op.escape());
} else {
self.repetitions -= 1;
match real_op.reset() {
Err(e) => return Some(Err(e)),
Ok(_) => {}
if let Err(e) = real_op.reset() {
return Some(Err(e));
}
}
} else {
// always reset in infinite loop mode
match real_op.reset() {
Err(e) => return Some(Err(e)),
Ok(_) => {}
if let Err(e) = real_op.reset() {
return Some(Err(e));
}
}
}

View file

@ -68,18 +68,16 @@ impl Sorter for BlissNextSorter {
let mut ctx = iterator.escape();
for i in 1..self.item_buf.len() {
let item = &self.item_buf[i];
match ctx.analysis.prepare_distance(first, item) {
Err(e) => {
iterator.enter(ctx);
return Err(e);
}
Ok(_) => {}
if let Err(e) = ctx.analysis.prepare_distance(first, item) {
iterator.enter(ctx);
return Err(e);
}
}
iterator.enter(ctx);
items_out.push_back(Ok(first.to_owned()));
}
} else {
#[allow(clippy::collapsible_else_if)]
if self.item_buf.len() > 2 {
let last = self.item_buf.pop_front().unwrap();
let mut best_index = 0;
@ -107,12 +105,9 @@ impl Sorter for BlissNextSorter {
let next = &self.item_buf[0];
for i in 1..self.item_buf.len() {
let item = &self.item_buf[i];
match ctx.analysis.prepare_distance(next, item) {
Err(e) => {
iterator.enter(ctx);
return Err(e);
}
Ok(_) => {}
if let Err(e) = ctx.analysis.prepare_distance(next, item) {
iterator.enter(ctx);
return Err(e);
}
}
iterator.enter(ctx);

View file

@ -64,12 +64,7 @@ impl Sorter for BlissSorter {
// when buf_len_old == item_buf.len(), iterator was already complete
// no need to sort in that case, since buffer was sorted in last call to sort or buffer never had any items to sort
if self.first_song.is_none() {
for item in item_buf.iter() {
if let Ok(item) = item {
self.first_song = Some(item.clone());
break;
}
}
self.first_song = item_buf.iter().flatten().next().map(|x| x.to_owned());
}
if let Some(first) = &self.first_song {
let mut ctx = iterator.escape();
@ -78,12 +73,9 @@ impl Sorter for BlissSorter {
if item == first {
continue;
}
match ctx.analysis.prepare_distance(first, item) {
Err(e) => {
iterator.enter(ctx);
return Err(e);
}
Ok(_) => {}
if let Err(e) = ctx.analysis.prepare_distance(first, item) {
iterator.enter(ctx);
return Err(e);
}
}
}
@ -115,8 +107,8 @@ impl Sorter for BlissSorter {
item_buf.make_contiguous().sort_by(|a, b| {
if let Ok(a) = a {
if let Ok(b) = b {
let float_a = cache.get(&a).unwrap();
let float_b = cache.get(&b).unwrap();
let float_a = cache.get(a).unwrap();
let float_b = cache.get(b).unwrap();
return float_a.partial_cmp(float_b).unwrap_or(DEFAULT_ORDER);
}
}

View file

@ -53,10 +53,10 @@ impl Sorter for ShuffleSorter {
}
}
// end case: everything is completely empty -- end loop without a new result
if item_buf.len() == 0 {
if item_buf.is_empty() {
return Ok(());
}
random = random % item_buf.len();
random %= item_buf.len();
}
}
}
@ -71,10 +71,10 @@ pub struct ShuffleSorterFactory;
impl SorterFactory<ShuffleSorter> for ShuffleSorterFactory {
fn is_sorter(&self, tokens: &VecDeque<&Token>) -> bool {
(!tokens.is_empty() && check_name("shuffle", &tokens[0]))
(!tokens.is_empty() && check_name("shuffle", tokens[0]))
|| (tokens.len() > 1
&& check_name("random", &tokens[0])
&& check_name("shuffle", &tokens[1]))
&& check_name("random", tokens[0])
&& check_name("shuffle", tokens[1]))
}
fn build_sorter(

View file

@ -65,7 +65,7 @@ impl Iterator for UnionStatement {
Err(e) => return Some(Err(e)),
};
real_op.enter(self.context.take().unwrap());
while let Some(item) = real_op.next() {
if let Some(item) = real_op.next() {
self.context = Some(real_op.escape());
return Some(item);
}

View file

@ -74,22 +74,21 @@ impl Iterator for AssignStatement {
Ok(real) => real,
Err(e) => return Some(Err(e)),
};
let result;
if self.is_declaration {
result = self
let result = if self.is_declaration {
self
.context
.as_mut()
.unwrap()
.variables
.declare(&self.variable_name, Type::Op(real));
.declare(&self.variable_name, Type::Op(real))
} else {
result = self
self
.context
.as_mut()
.unwrap()
.variables
.assign(&self.variable_name, Type::Op(real));
}
.assign(&self.variable_name, Type::Op(real))
};
match result {
Ok(_) => None,
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),
@ -107,22 +106,21 @@ impl Iterator for AssignStatement {
}))*/
} else {
let assign_type = self.assign_type.clone().unwrap();
let result;
if self.is_declaration {
result = self
let result = if self.is_declaration {
self
.context
.as_mut()
.unwrap()
.variables
.declare(&self.variable_name, Type::Primitive(assign_type));
.declare(&self.variable_name, Type::Primitive(assign_type))
} else {
result = self
self
.context
.as_mut()
.unwrap()
.variables
.assign(&self.variable_name, Type::Primitive(assign_type));
}
.assign(&self.variable_name, Type::Primitive(assign_type))
};
match result {
Ok(_) => None,
Err(e) => Some(Err(e.with(RuntimeOp(PseudoOp::from_printable(self))))),

View file

@ -246,6 +246,8 @@
//! Load an item from file, populating the item with the song's tags.
//!
#![allow(clippy::redundant_field_names)]
mod context;
mod debug;
mod errors;

View file

@ -36,6 +36,10 @@ impl Library {
self.songs.len()
}
pub fn is_empty(&self) -> bool {
self.songs.is_empty()
}
pub fn clear_modified(&mut self) {
self.dirty = false;
}
@ -54,7 +58,7 @@ impl Library {
self.files.contains(&path.as_ref().to_path_buf())
}
pub fn all_songs<'a>(&'a self) -> Vec<&'a DbMusicItem> {
pub fn all_songs(&self) -> Vec<&'_ DbMusicItem> {
self.songs.values().collect()
}
@ -67,7 +71,7 @@ impl Library {
self.songs.insert(song.song_id, song);
}
pub fn all_metadata<'a>(&'a self) -> Vec<&'a DbMetaItem> {
pub fn all_metadata(& self) -> Vec<&'_ DbMetaItem> {
self.metadata.values().collect()
}
@ -77,7 +81,7 @@ impl Library {
self.metadata.insert(meta.meta_id, meta);
}
pub fn all_artists<'a>(&'a self) -> Vec<&'a DbArtistItem> {
pub fn all_artists(&self) -> Vec<&'_ DbArtistItem> {
self.artists.values().collect()
}
@ -88,7 +92,7 @@ impl Library {
.insert(Self::sanitise_key(&artist.name), artist);
}
pub fn all_albums<'a>(&'a self) -> Vec<&'a DbAlbumItem> {
pub fn all_albums(&self) -> Vec<&'_ DbAlbumItem> {
self.albums.values().collect()
}
@ -98,7 +102,7 @@ impl Library {
self.albums.insert(Self::sanitise_key(&album.title), album);
}
pub fn all_genres<'a>(&'a self) -> Vec<&'a DbGenreItem> {
pub fn all_genres(&self) -> Vec<&'_ DbGenreItem> {
self.genres.values().collect()
}
@ -236,7 +240,7 @@ impl Library {
}
#[inline]
fn find_or_gen_id<'a, D: DatabaseObj>(map: &'a HashMap<String, D>, key: &str) -> u64 {
fn find_or_gen_id<D: DatabaseObj>(map: &HashMap<String, D>, key: &str) -> u64 {
if let Some(obj) = Self::find_by_key(map, key) {
obj.id()
} else {

View file

@ -49,7 +49,7 @@ impl Tags {
.file_name()
.and_then(|file| file.to_str())
.map(|file| file.replacen(&format!(".{}", extension), "", 1))
.unwrap_or("Unknown Title".into())
.unwrap_or_else(|| "Unknown Title".into())
}
#[inline]
@ -149,7 +149,7 @@ impl Tags {
pub fn artist(&self, id: u64, genre_id: u64) -> DbArtistItem {
DbArtistItem {
artist_id: id,
name: self.artist_name().unwrap_or("Unknown Artist".into()),
name: self.artist_name().unwrap_or_else(|| "Unknown Artist".into()),
genre: genre_id,
}
}
@ -171,7 +171,7 @@ impl Tags {
pub fn album(&self, id: u64, meta_id: u64, artist_id: u64, genre_id: u64) -> DbAlbumItem {
DbAlbumItem {
album_id: id,
title: self.album_title().unwrap_or("Unknown Album".into()),
title: self.album_title().unwrap_or_else(|| "Unknown Album".into()),
metadata: meta_id,
artist: artist_id,
genre: genre_id,
@ -212,7 +212,7 @@ impl Tags {
pub fn genre(&self, id: u64) -> DbGenreItem {
DbGenreItem {
genre_id: id,
title: self.genre_title().unwrap_or("Unknown Genre".into()),
title: self.genre_title().unwrap_or_else(|| "Unknown Genre".into()),
}
}
}

View file

@ -41,10 +41,11 @@ impl Iterator for SortedReadDir {
}
}
self.dir_iter_complete = true;
self.cache.sort_by(
self.cache.sort_by_key(|b| std::cmp::Reverse(b.path().to_string_lossy().to_lowercase()));
/*self.cache.sort_by(
|a, b| b.path().to_string_lossy().to_lowercase().cmp(
&a.path().to_string_lossy().to_lowercase())
);
);*/
}
if self.cache.is_empty() {
None
@ -73,7 +74,7 @@ impl Display for FileIter {
self.pattern
.as_ref()
.map(|re| re.to_string())
.unwrap_or("[none]".to_string()),
.unwrap_or_else(|| "[none]".to_string()),
self.recursive
)
}
@ -224,13 +225,11 @@ impl FileIter {
) {
// populates fields from named capture groups
if let Some(captures) = captures {
for name_maybe in capture_names {
if let Some(name) = name_maybe {
if item.field(name).is_some() {
for name in capture_names.flatten() {
if item.field(name).is_some() {
// do nothing
} else if let Some(value) = captures.name(name).map(|m| m.as_str().to_string()) {
item.set_field(name, TypePrimitive::parse(value));
}
} else if let Some(value) = captures.name(name).map(|m| m.as_str().to_string()) {
item.set_field(name, TypePrimitive::parse(value));
}
}
}

View file

@ -41,7 +41,7 @@ impl MpdQuerier for MpdExecutor {
query_mut = query_mut.and(str_to_term(term), value);
}
let songs = self.connection.as_mut().unwrap().search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
Ok(songs.into_iter().map(|x| song_to_item(x)).collect())
Ok(songs.into_iter().map(song_to_item).collect())
}
fn one_shot_search(&self, addr: SocketAddr, params: Vec<(&str, String)>) -> Result<VecDeque<Item>, RuntimeMsg> {
@ -53,7 +53,7 @@ impl MpdQuerier for MpdExecutor {
query_mut = query_mut.and(str_to_term(term), value);
}
let songs = connection.search(query_mut, None).map_err(|e| RuntimeMsg(format!("MPD search error: {}", e)))?;
Ok(songs.into_iter().map(|x| song_to_item(x)).collect())
Ok(songs.into_iter().map(song_to_item).collect())
}
}
@ -95,7 +95,7 @@ fn song_to_item(song: Song) -> Item {
}
#[inline]
fn str_to_term<'a>(s: &'a str) -> Term<'a> {
fn str_to_term(s: &str) -> Term<'_> {
match s {
"any" => Term::Any,
"file" => Term::File,

View file

@ -208,7 +208,7 @@ enum ResponseType {
},
Song {
path: String,
song: Result<Song, BlissError>,
song: Result<Box<Song>, BlissError>,
},
UnsupportedSong {
path: String,
@ -257,13 +257,13 @@ impl CacheThread {
}
}
fn insert_song(&mut self, path: String, song_result: Result<Song, BlissError>) {
fn insert_song(&mut self, path: String, song_result: Result<Box<Song>, BlissError>) {
self.song_in_progress.remove(&path);
if self.song_cache.len() > MAX_SONG_CACHE_SIZE {
// avoid using too much memory -- songs are big memory objects
self.song_cache.clear();
}
self.song_cache.insert(path, song_result);
self.song_cache.insert(path, song_result.map(|x| x.as_ref().to_owned()));
}
fn insert_distance(
@ -305,7 +305,7 @@ impl CacheThread {
if result.is_none() && auto_add {
self.song_in_progress.insert(path.to_owned());
}
return result;
return result.map(|x| x.as_ref().to_owned());
} else {
self.insert_song(path2, song);
}
@ -322,7 +322,7 @@ impl CacheThread {
let result = self
.song_cache
.get(path)
.and_then(|r| r.clone().ok().to_owned());
.and_then(|r| r.clone().ok());
if result.is_none() && auto_add {
self.song_in_progress.insert(path.to_owned());
}
@ -331,7 +331,7 @@ impl CacheThread {
if auto_add {
self.song_in_progress.insert(path.to_owned());
}
return None;
None
}
fn handle_distance_req(
@ -346,11 +346,11 @@ impl CacheThread {
if let Some(result) = self.distance_cache.get(&key) {
if ack {
let result = result.to_owned();
if let Err(_) = self.responses.send(ResponseType::Distance {
if self.responses.send(ResponseType::Distance {
path1: path1,
path2: path2,
distance: result,
}) {
}).is_err() {
return true;
}
}
@ -360,14 +360,12 @@ impl CacheThread {
// also prevents deadlock in self.get_song_option()
// due to waiting on song that isn't being processed yet
// (first call adds it to song_in_progress set, second call just waits)
if ack {
if let Err(_) = self.responses.send(ResponseType::Distance {
if ack && self.responses.send(ResponseType::Distance {
path1: path1,
path2: path2,
distance: Ok(0.0),
}) {
return true;
}
}).is_err() {
return true;
}
} else if !self.distance_in_progress.contains(&key) {
// distance worker uses 3 threads (it's own thread + 1 extra per song) for 2 songs
@ -433,11 +431,11 @@ impl CacheThread {
distance.clone(),
);
if path1_2 == key.0 && path2_2 == key.1 {
if let Err(_) = self.responses.send(ResponseType::Distance {
if self.responses.send(ResponseType::Distance {
path1: path1_2,
path2: path2_2,
distance: distance,
}) {
}).is_err() {
return true;
}
break 'inner1;
@ -448,10 +446,10 @@ impl CacheThread {
},
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
self.song_in_progress.remove(&unsupported_path);
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
if self.responses.send(ResponseType::UnsupportedSong {
path: unsupported_path.clone(),
msg: msg
}) {
}).is_err() {
return true;
}
if unsupported_path == key.0 || unsupported_path == key.1 {
@ -478,10 +476,10 @@ impl CacheThread {
} else if !path.contains("://") {
path
} else {
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
if self.responses.send(ResponseType::UnsupportedSong {
msg: format!("Song path is not a supported URI, it's `{}`", path),
path: path,
}) {
}).is_err() {
return true;
}
return false;
@ -489,10 +487,10 @@ impl CacheThread {
if let Some(song) = self.song_cache.get(&path) {
if ack {
let song = song.to_owned();
if let Err(_) = self.responses.send(ResponseType::Song {
if self.responses.send(ResponseType::Song {
path: path,
song: song,
}) {
song: song.map(Box::new),
}).is_err() {
return true;
}
}
@ -539,7 +537,7 @@ impl CacheThread {
results
.send(ResponseType::Song {
path: path_clone,
song: song_result,
song: song_result.map(Box::new),
})
.unwrap_or(());
});
@ -557,10 +555,10 @@ impl CacheThread {
ResponseType::Song { path: path2, song } => {
self.insert_song(path2.clone(), song.clone());
if path2 == path {
if let Err(_) = self.responses.send(ResponseType::Song {
if self.responses.send(ResponseType::Song {
path: path,
song: song,
}) {
}).is_err() {
return true;
}
break 'inner3;
@ -569,10 +567,10 @@ impl CacheThread {
ResponseType::UnsupportedSong { path: unsupported_path, msg } => {
self.song_in_progress.remove(&unsupported_path);
if unsupported_path == path {
if let Err(_) = self.responses.send(ResponseType::UnsupportedSong {
if self.responses.send(ResponseType::UnsupportedSong {
path: unsupported_path,
msg: msg
}) {
}).is_err() {
return true;
}
break 'inner3;
@ -624,7 +622,7 @@ fn worker_distance(
results
.send(ResponseType::Song {
path: path1.to_string(),
song: new_song1.clone(),
song: new_song1.clone().map(Box::new),
})
.unwrap_or(());
new_song1?
@ -637,7 +635,7 @@ fn worker_distance(
results
.send(ResponseType::Song {
path: path2.to_string(),
song: new_song2.clone(),
song: new_song2.clone().map(Box::new),
})
.unwrap_or(());
if new_song2.is_err() {

View file

@ -1,4 +1,5 @@
use core::fmt::Debug;
use std::fmt::Write;
use std::collections::{HashMap, HashSet};
use crate::lang::db::*;
@ -159,9 +160,11 @@ impl DatabaseQuerier for SQLiteExecutor {
for key in keys.drain() {
if first {
first = false;
concat_keys += key;
write!(concat_keys, "{}", key).unwrap();
//concat_keys += key;
} else {
concat_keys += &format!("{}, ", key);
write!(concat_keys, "{}, ", key).unwrap();
//concat_keys += &format!("{}, ", key);
}
}
return Err(RuntimeMsg(format!(

View file

@ -1,3 +1,4 @@
#![allow(clippy::match_like_matches_macro)]
mod error;
mod token_enum;
mod tokenizer;

View file

@ -268,7 +268,7 @@ impl ReaderStateMachine {
Self::Escaped { inside } => match inside {
'`' => Self::InsideTickLiteral { out: input },
'"' => Self::InsideQuoteLiteral { out: input },
'_' | _ => Self::Regular { out: input },
_ => Self::Regular { out: input },
},
Self::StartTickLiteral {} | Self::InsideTickLiteral { .. } => match input_char {
'\\' => Self::Escaped { inside: '`' },

View file

@ -1,5 +1,5 @@
use std::fmt::{Debug, Display, Error, Formatter};
use std::convert::Into;
use std::convert::From;
#[derive(Debug, Clone)]
pub enum PlayerError {
@ -58,9 +58,9 @@ impl Display for PlaybackError {
}
}
impl Into<PlayerError> for PlaybackError {
fn into(self) -> PlayerError {
PlayerError::Playback(self)
impl From<PlaybackError> for PlayerError {
fn from(other: PlaybackError) -> Self {
PlayerError::Playback(other)
}
}
@ -86,8 +86,8 @@ impl Display for UriError {
}
}
impl Into<PlayerError> for UriError {
fn into(self) -> PlayerError {
PlayerError::Uri(self)
impl From<UriError> for PlayerError {
fn from(other: UriError) -> Self {
PlayerError::Uri(other)
}
}

View file

@ -3,6 +3,9 @@
//! Music playback and m3u8 playlist generation are implemented in this part of the project.
//!
#![allow(clippy::match_like_matches_macro)]
#![allow(clippy::redundant_field_names)]
mod controller;
mod errors;
pub(crate) mod os_controls;

View file

@ -165,7 +165,7 @@ impl<I: std::iter::Iterator<Item=Result<Item, InterpreterError>>> PlayerServer<I
pub fn unblocking_timer_loop(ctrl_tx: Sender<ControlAction>, sleep_ms: u64) {
let dur = std::time::Duration::from_millis(sleep_ms);
loop {
if let Err(_) = ctrl_tx.send(ControlAction::NoOp { ack: false }) {
if ctrl_tx.send(ControlAction::NoOp { ack: false }).is_err() {
break;
}
thread::sleep(dur);

View file

@ -15,9 +15,9 @@ impl<'a> Uri<&'a str> {
match self.0.find("//") {
Some(end) => {
// proper URI
if let Some(query_start) = self.0.find("?") {
if let Some(query_start) = self.0.find('?') {
self.0.get(end+2..query_start).unwrap()
} else if let Some(frag_start) = self.0.find("#") {
} else if let Some(frag_start) = self.0.find('#') {
self.0.get(end+2..frag_start).unwrap()
} else {
self.0.get(end+2..).unwrap()

View file

@ -80,7 +80,7 @@ fn main() {
}
// build playback controller
let script_file2 = script_file.clone();
let volume = args.volume.clone();
let volume = args.volume;
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
Ok(mpd) => mpd,
Err(e) => panic!("Abort: Cannot connect to MPD: {}", e),

View file

@ -1,4 +1,5 @@
//! Read, Execute, Print Loop functionality
#![allow(clippy::single_match)]
use std::sync::{RwLock};
use std::sync::mpsc::{self, Receiver};
use std::io::{self, Write};
@ -79,7 +80,7 @@ impl ReplState {
}
}
fn interpreter_event_callback<'a, T: muss_interpreter::tokens::TokenReader>(_interpreter: &mut Interpreter<'a, T>, event: InterpreterEvent) -> Result<(), InterpreterError> {
fn interpreter_event_callback<T: muss_interpreter::tokens::TokenReader>(_interpreter: &mut Interpreter<'_, T>, event: InterpreterEvent) -> Result<(), InterpreterError> {
match event {
InterpreterEvent::StatementComplete => {
if let Ok(mut d_state) = DEBUG_STATE.write() {
@ -165,7 +166,7 @@ pub fn repl(args: CliArgs) {
let term = Term::stdout();
term.set_title("muss");
let (writer, reader) = channel_io();
let volume = args.volume.clone();
let volume = args.volume;
let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
Ok(mpd) => mpd,
Err(e) => {
@ -187,7 +188,7 @@ pub fn repl(args: CliArgs) {
match flag {
DebugFlag::Normal => item,
DebugFlag::Skip => {
while let Some(_) = interpretor.next() {
for _ in interpretor.by_ref() {
// NOTE: recursion occurs here
}
None
@ -195,7 +196,7 @@ pub fn repl(args: CliArgs) {
DebugFlag::List => {
if let Some(x) = item {
list_tx.send(x.map_err(|e| e.to_string())).unwrap_or(());
while let Some(x) = interpretor.next() {
for x in interpretor.by_ref() {
// NOTE: recursion occurs here
// in most cases this will never be a case of Some(...) because
// recursive calls to this function intercept it first and return None
@ -241,10 +242,10 @@ pub fn repl(args: CliArgs) {
match player.save_m3u8(&mut playlist_writer) {
Ok(_) => {}
Err(e) => {
error_prompt(e, &args);
error_prompt(e, args);
// consume any further errors (this shouldn't actually write anything)
while let Err(e) = player.save_m3u8(&mut playlist_writer) {
error_prompt(e, &args);
error_prompt(e, args);
}
}
}
@ -266,7 +267,7 @@ pub fn repl(args: CliArgs) {
if args.wait {
match ctrl.wait_for_empty() {
Ok(_) => {}
Err(e) => error_prompt(e, &args),
Err(e) => error_prompt(e, args),
}
} else {
// consume all incoming errors
@ -274,7 +275,7 @@ pub fn repl(args: CliArgs) {
while had_err {
let mut new_had_err = false;
for e in ctrl.check_ack() {
error_prompt(e, &args);
error_prompt(e, args);
new_had_err = true;
}
had_err = new_had_err;
@ -354,7 +355,7 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
if !statement_result.starts_with('?') {
state
.writer
.write(state.statement_buf.iter().collect::<String>().as_bytes())
.write_all(state.statement_buf.iter().collect::<String>().as_bytes())
.expect(INTERPRETER_WRITE_ERROR);
execute(state, args);
state.statement_buf.clear();
@ -427,57 +428,55 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
}
}
}
} else {
if state.current_line.len() != state.cursor_rightward_position {
// if not at start of line
let removed_char = state
.current_line
.remove(state.current_line.len() - state.cursor_rightward_position - 1);
state.statement_buf.remove(
state.statement_buf.len() - state.cursor_rightward_position - 1,
);
// re-sync unclosed syntax tracking
match removed_char {
'"' | '`' => {
if let Some(c2) = state.in_literal {
if removed_char == c2 {
state.in_literal = None;
}
} else {
state.in_literal = Some(removed_char);
} else if state.current_line.len() != state.cursor_rightward_position {
// if not at start of line
let removed_char = state
.current_line
.remove(state.current_line.len() - state.cursor_rightward_position - 1);
state.statement_buf.remove(
state.statement_buf.len() - state.cursor_rightward_position - 1,
);
// re-sync unclosed syntax tracking
match removed_char {
'"' | '`' => {
if let Some(c2) = state.in_literal {
if removed_char == c2 {
state.in_literal = None;
}
} else {
state.in_literal = Some(removed_char);
}
'(' => {
if state.bracket_depth != 0 {
state.bracket_depth -= 1
}
}
')' => state.bracket_depth += 1,
'{' => {
if state.curly_depth != 0 {
state.curly_depth -= 1
}
}
'}' => state.curly_depth += 1,
_ => {}
}
// re-print end of line to remove character in middle
state
.terminal
.move_cursor_left(1)
.expect(TERMINAL_WRITE_ERROR);
for i in state.current_line.len() - state.cursor_rightward_position
..state.current_line.len()
{
write!(state.terminal, "{}", state.current_line[i])
.expect(TERMINAL_WRITE_ERROR);
'(' => {
if state.bracket_depth != 0 {
state.bracket_depth -= 1
}
}
write!(state.terminal, " ").expect(TERMINAL_WRITE_ERROR);
state
.terminal
.move_cursor_left(state.cursor_rightward_position + 1)
')' => state.bracket_depth += 1,
'{' => {
if state.curly_depth != 0 {
state.curly_depth -= 1
}
}
'}' => state.curly_depth += 1,
_ => {}
}
// re-print end of line to remove character in middle
state
.terminal
.move_cursor_left(1)
.expect(TERMINAL_WRITE_ERROR);
for i in state.current_line.len() - state.cursor_rightward_position
..state.current_line.len()
{
write!(state.terminal, "{}", state.current_line[i])
.expect(TERMINAL_WRITE_ERROR);
}
write!(state.terminal, " ").expect(TERMINAL_WRITE_ERROR);
state
.terminal
.move_cursor_left(state.cursor_rightward_position + 1)
.expect(TERMINAL_WRITE_ERROR);
}
}
Key::Del => {
@ -547,7 +546,7 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
let complete_statement = state.statement_buf.iter().collect::<String>();
state
.writer
.write(complete_statement.as_bytes())
.write_all(complete_statement.as_bytes())
.expect("Failed to write to MPS interpreter");
execute(state, args);
state.statement_buf.clear();
@ -575,23 +574,27 @@ fn read_loop<F: FnMut(&mut ReplState, &CliArgs)>(args: &CliArgs, state: &mut Rep
}
}
Key::ArrowDown => {
if state.selected_history > 1 {
state.selected_history -= 1;
display_history_line(state, args);
} else if state.selected_history == 1 {
state.selected_history = 0;
state.line_number -= 1;
state
.terminal
.clear_line()
.expect(TERMINAL_WRITE_ERROR);
prompt(state, args);
// clear stale input buffer
state.statement_buf.clear();
state.current_line.clear();
state.in_literal = None;
state.bracket_depth = 0;
state.curly_depth = 0;
match state.selected_history {
1 => {
state.selected_history = 0;
state.line_number -= 1;
state
.terminal
.clear_line()
.expect(TERMINAL_WRITE_ERROR);
prompt(state, args);
// clear stale input buffer
state.statement_buf.clear();
state.current_line.clear();
state.in_literal = None;
state.bracket_depth = 0;
state.curly_depth = 0;
},
0 => {},
_ => {
state.selected_history -= 1;
display_history_line(state, args);
},
}
}
Key::ArrowLeft => {
@ -642,7 +645,7 @@ fn display_history_line(state: &mut ReplState, args: &CliArgs) {
let new_statement = state.history[state.history.len() - state.selected_history].trim();
state
.terminal
.write(new_statement.as_bytes())
.write_all(new_statement.as_bytes())
.expect(TERMINAL_WRITE_ERROR);
// clear stale input buffer
state.statement_buf.clear();