use std::{fmt::Display, marker::PhantomData, sync::Arc};
use duat_core::{
buffer::Buffer,
context::{self, Handle},
data::{DataMap, Pass, RwData},
mode::{Selection, Selections},
text::{AsBuilderPart, Builder, Inlay, Spacer, Text},
ui::{Area, Window},
};
use crate::widgets::status_line::CheckerFn;
enum Appender<Part: AsBuilderPart<D, _T> = String, _T = (), D: Display = String> {
FromFn(BuilderFn),
Part(Part, PhantomData<(D, _T)>),
}
#[doc(hidden)]
pub struct State<_T1 = (), Part: AsBuilderPart<D, _T2> = String, _T2 = (), D: Display = String> {
appender: Appender<Part, _T2, D>,
checker: Option<Box<dyn Fn() -> bool + Send + Sync>>,
ghost: PhantomData<_T1>,
}
impl<_T1, Part, _T2, D> State<_T1, Part, _T2, D>
where
Part: AsBuilderPart<D, _T2> + Send + 'static,
_T2: 'static,
D: Display + 'static,
{
pub fn fns(self) -> StateFns {
(
match self.appender {
Appender::FromFn(f) => f,
Appender::Part(part, _) => {
Box::new(move |_, b, _| b.push_builder_part(part.as_builder_part()))
}
},
Arc::new(move || self.checker.as_ref().is_some_and(|check| check())),
)
}
}
impl<D: Display + Send + 'static> From<D> for State<D, D, D, D> {
fn from(value: D) -> Self {
Self {
appender: Appender::Part(value, PhantomData),
checker: None,
ghost: PhantomData,
}
}
}
impl From<Text> for State<(), Text> {
fn from(value: Text) -> Self {
Self {
appender: Appender::Part(value, PhantomData),
checker: None,
ghost: PhantomData,
}
}
}
impl<D: Display + Send + 'static> From<RwData<D>> for State<DataArg<D>, D, D, D> {
fn from(value: RwData<D>) -> Self {
let checker = value.checker();
Self {
appender: Appender::FromFn(Box::new(move |pa, b, _| b.push(value.read(pa)))),
checker: Some(Box::new(checker)),
ghost: PhantomData,
}
}
}
impl From<RwData<Text>> for State<DataArg<()>, Text> {
fn from(value: RwData<Text>) -> Self {
let checker = value.checker();
Self {
appender: Appender::FromFn(Box::new(move |pa, b, _| b.push(value.read(pa).clone()))),
checker: Some(Box::new(checker)),
ghost: PhantomData,
}
}
}
impl<I: ?Sized, O: Display> From<DataMap<I, O>> for State<DataArg<O>, O, O, O> {
fn from(value: DataMap<I, O>) -> Self {
let checker = value.checker();
State {
appender: Appender::FromFn(Box::new(move |pa, b, _| b.push(value.call(pa)))),
checker: Some(Box::new(checker)),
ghost: PhantomData,
}
}
}
impl<I: ?Sized> From<DataMap<I, Text>> for State<DataArg<Text>, Text> {
fn from(value: DataMap<I, Text>) -> Self {
let checker = value.checker();
State {
appender: Appender::FromFn(Box::new(move |pa, b, _| b.push(value.call(pa)))),
checker: Some(Box::new(checker)),
ghost: PhantomData,
}
}
}
impl From<Spacer> for State<Spacer, Spacer> {
fn from(_: Spacer) -> Self {
Self {
appender: Appender::Part(Spacer, PhantomData),
checker: None,
ghost: PhantomData,
}
}
}
impl From<Inlay> for State<(), Inlay> {
fn from(value: Inlay) -> Self {
Self {
appender: Appender::Part(value, PhantomData),
checker: None,
ghost: PhantomData,
}
}
}
macro_rules! implFromFn {
($($arg:ident),*) => {
#[allow(unused_parens, non_snake_case)]
impl<Fmt, D, $($arg),*> From<Fmt> for State<FnArg<($($arg),*), D>, D, D, D>
where
Fmt: Fn($(&$arg),*) -> D + Send + 'static,
D: Display,
$($arg: StateArg),*
{
#[allow(unused_variables)]
fn from(value: Fmt) -> Self {
Self {
appender: Appender::FromFn(Box::new(move |pa, b, handle| {
$(
let $arg = $arg::get(pa, handle);
)*
b.push(value($($arg),*));
})),
checker: None,
ghost: PhantomData,
}
}
}
#[allow(unused_parens, non_snake_case)]
impl<Fmt, $($arg),*> From<Fmt> for State<FnArg<($($arg),*), Text>, Text>
where
Fmt: Fn($(&$arg),*) -> Text + Send + 'static,
$($arg: StateArg),*
{
#[allow(unused_variables)]
fn from(value: Fmt) -> Self {
Self {
appender: Appender::FromFn(Box::new(move |pa, b, handle| {
$(
let $arg = $arg::get(pa, handle);
)*
b.push(value($($arg),*));
})),
checker: None,
ghost: PhantomData,
}
}
}
}
}
implFromFn!();
implFromFn!(Arg1);
implFromFn!(Arg1, Arg2);
implFromFn!(Arg1, Arg2, Arg3);
implFromFn!(Arg1, Arg2, Arg3, Arg4);
implFromFn!(Arg1, Arg2, Arg3, Arg4, Arg5);
implFromFn!(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
implFromFn!(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7);
implFromFn!(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8);
trait StateArg {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self;
}
impl StateArg for Buffer {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
handle.read(pa)
}
}
impl StateArg for Handle {
fn get<'a>(_: &'a Pass, handle: &'a Handle) -> &'a Self {
handle
}
}
impl StateArg for Area {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
handle.area().read(pa)
}
}
impl StateArg for Pass {
fn get<'a>(pa: &'a Pass, _: &'a Handle) -> &'a Self {
pa
}
}
impl StateArg for Text {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
handle.text(pa)
}
}
impl StateArg for Selections {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
handle.text(pa).selections()
}
}
impl StateArg for Selection {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
handle.text(pa).main_sel()
}
}
impl StateArg for Window {
fn get<'a>(pa: &'a Pass, handle: &'a Handle) -> &'a Self {
context::windows()
.iter(pa)
.find(|window| window.handles(pa).any(|h| h == handle))
.unwrap()
}
}
#[doc(hidden)]
#[derive(Clone)]
pub struct DataArg<T>(PhantomData<T>);
#[doc(hidden)]
pub struct FnArg<Args, T>(PhantomData<(Args, T)>);
impl<Args, T> Clone for FnArg<Args, T> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}
unsafe impl<Args, T> Send for FnArg<Args, T> {}
type BuilderFn = Box<dyn Fn(&Pass, &mut Builder, &Handle) + Send>;
type StateFns = (BuilderFn, CheckerFn);