Fix clippy warnings & errors
This commit is contained in:
parent
2bec331700
commit
2b6c47f166
52 changed files with 305 additions and 304 deletions
|
@ -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),
|
||||
|
|
11
interpreter/fuzz/Cargo.lock
generated
11
interpreter/fuzz/Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -53,6 +53,7 @@ impl LanguageDictionary {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for LanguageDictionary {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::match_like_matches_macro)]
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
mod db_items;
|
||||
mod dictionary;
|
||||
mod error;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(clippy::borrowed_box)]
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
|
||||
use super::Op;
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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, "}}")
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(clippy::while_let_on_iterator)]
|
||||
mod empties;
|
||||
pub(crate) mod empty;
|
||||
mod files;
|
||||
|
|
|
@ -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>) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))))),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(clippy::match_like_matches_macro)]
|
||||
mod error;
|
||||
mod token_enum;
|
||||
mod tokenizer;
|
||||
|
|
|
@ -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: '`' },
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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),
|
||||
|
|
149
src/repl.rs
149
src/repl.rs
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue