fend 1.5.8

Arbitrary-precision unit-aware calculator
use tokio::runtime::Handle;

use crate::{config, context::Context};

pub struct Hint(String);

impl rustyline::hint::Hint for Hint {
	fn display(&self) -> &str {
		self.0.as_str()
	}

	fn completion(&self) -> Option<&str> {
		None
	}
}

pub struct Helper<'a> {
	ctx: Context<'a>,
	config: &'a config::Config,
}

impl<'a> Helper<'a> {
	pub fn new(ctx: Context<'a>, config: &'a config::Config) -> Self {
		Self { ctx, config }
	}
}

impl rustyline::hint::Hinter for Helper<'_> {
	type Hint = Hint;

	fn hint(&self, line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<Hint> {
		tokio::task::block_in_place(|| {
			let rt = Handle::current();
			rt.block_on(async {
				let result = self.ctx.eval_hint(line).await;
				let s = result.get_main_result();
				Some(if s.is_empty() {
					return None;
				} else if self.config.enable_colors {
					Hint(format!(
						"\n{}",
						crate::print_spans(result.get_main_result_spans().collect(), self.config)
					))
				} else {
					Hint(format!("\n{s}"))
				})
			})
		})
	}
}

impl rustyline::highlight::Highlighter for Helper<'_> {}

impl rustyline::validate::Validator for Helper<'_> {}

#[derive(Debug)]
pub struct FendCandidate {
	completion: fend_core::Completion,
}
impl rustyline::completion::Candidate for FendCandidate {
	fn display(&self) -> &str {
		self.completion.display()
	}
	fn replacement(&self) -> &str {
		self.completion.insert()
	}
}

impl rustyline::completion::Completer for Helper<'_> {
	type Candidate = FendCandidate;

	fn complete(
		&self,
		line: &str,
		pos: usize,
		_ctx: &rustyline::Context<'_>,
	) -> rustyline::Result<(usize, Vec<Self::Candidate>)> {
		let (pos, completions) = fend_core::get_completions_for_prefix(&line[..pos]);
		let v: Vec<_> = completions
			.into_iter()
			.map(|c| FendCandidate { completion: c })
			.collect();
		Ok((pos, v))
	}
}

impl rustyline::Helper for Helper<'_> {}