#![feature(
decl_macro,
closure_lifetime_binder,
default_field_values,
associated_type_defaults
)]
use duat_core::prelude::*;
use regex_syntax::ast::Ast;
pub mod modes;
pub mod state;
pub mod widgets;
pub mod hooks {
use duat_core::hook::Hookable;
pub struct SearchUpdated(pub(crate) (String, String));
impl Hookable for SearchUpdated {
type Input<'h> = (&'h str, &'h str);
fn get_input(&mut self) -> Self::Input<'_> {
(&self.0.0, &self.0.1)
}
}
pub struct SearchPerformed(pub(crate) String);
impl Hookable for SearchPerformed {
type Input<'h> = &'h str;
fn get_input(&mut self) -> Self::Input<'_> {
&self.0
}
}
}
fn tag_from_ast(tagger: Tagger, text: &mut Text, ast: &Ast) {
use duat_core::form::FormId;
use regex_syntax::ast::{Ast::*, Span};
let mut insert_form = |id: FormId, span: Span| {
text.insert_tag(tagger, span.start.offset..span.end.offset, id.to_tag(0));
};
match ast {
Empty(_) => {}
Flags(set_flags) => {
let id = form::id_of!("regex.operator.flags");
insert_form(id, set_flags.span);
}
Literal(literal) => {
let id = form::id_of!("regex.literal");
insert_form(id, literal.span);
}
Dot(span) => {
let id = form::id_of!("regex.operator.dot");
insert_form(id, **span);
}
Assertion(assertion) => {
let id = form::id_of!("regex.operator.assertion");
insert_form(id, assertion.span);
}
ClassUnicode(class) => {
let id = form::id_of!("regex.class.unicode");
insert_form(id, class.span);
}
ClassPerl(class) => {
let id = form::id_of!("regex.class.perl");
insert_form(id, class.span);
}
ClassBracketed(class) => {
let class_id = form::id_of!("regex.class.bracketed");
let bracket_id = form::id_of!("regex.bracket.class");
insert_form(class_id, *class.kind.span());
let range = class.span.start.offset..class.span.start.offset + 1;
text.insert_tag(tagger, range, bracket_id.to_tag(0));
let range = class.span.end.offset - 1..class.span.end.offset;
text.insert_tag(tagger, range, bracket_id.to_tag(0));
}
Repetition(repetition) => {
let id = form::id_of!("regex.operator.repetition");
insert_form(id, repetition.op.span);
}
Group(group) => {
let group_id = form::id_of!("regex.group");
let bracket_id = form::id_of!("regex.bracket.group");
insert_form(group_id, *group.ast.span());
let range = group.span.start.offset..group.span.start.offset + 1;
text.insert_tag(tagger, range, bracket_id.to_tag(0));
let range = group.span.end.offset - 1..group.span.end.offset;
text.insert_tag(tagger, range, bracket_id.to_tag(0));
tag_from_ast(tagger, text, &group.ast);
}
Alternation(alternation) => {
let id = form::id_of!("regex.operator.alternation");
let mut prev_end = None;
for ast in alternation.asts.iter() {
tag_from_ast(tagger, text, ast);
if let Some(end) = prev_end {
let range = end..ast.span().start.offset;
text.insert_tag(tagger, range, id.to_tag(0));
}
prev_end = Some(ast.span().end.offset);
}
}
Concat(concat) => {
for ast in concat.asts.iter() {
tag_from_ast(tagger, text, ast);
}
}
}
}
mod private_exports {
pub use duat_core;
pub use format_like::format_like;
pub macro parse_str($appender_checker:expr, $str:literal) {{
use crate::{
private_exports::duat_core::{context::Handle, data::Pass, file::File, text::Builder},
widgets::State,
};
let (mut appender, checker) = $appender_checker;
let (mut ap, _) = State::from($str).fns();
let appender = move |pa: &Pass, builder: &mut Builder, reader: &Handle<File<_>, _>| {
appender(pa, builder, reader);
ap(pa, builder, reader);
};
(appender, checker)
}}
pub macro parse_status_part {
($appender_checker:expr, "", $part:expr) => {{
use crate::{
private_exports::duat_core::{
context::Handle, data::Pass, file::File, text::Builder
},
widgets::State,
};
#[allow(unused_mut)]
let (mut appender, checker) = $appender_checker;
let (ap, ch) = State::from($part).fns();
let checker = move |pa: &Pass| checker(pa) || ch(pa);
let appender = move |pa: &Pass, builder: &mut Builder, handle: &Handle<File<_>, _>| {
appender(pa, builder, handle);
ap(pa, builder, handle);
};
(appender, checker)
}},
($appender_checker:expr, $modif:literal, $part:expr) => {{
use crate::{
private_exports::duat_core::{
context::Handle, data::Pass, file::File, text::Builder
},
widgets::State,
};
let (mut appender, checker) = $appender_checker;
let (ap, ch) = State::from(format!(concat!("{:", $modif, "}"), $part)).fns();
let checker = move |pa: &Pass| checker(pa) || ch(pa);
let appender = move |pa: &Pass, builder: &mut Builder, handle: &Handle<File<_>, _>| {
appender(pa, builder, handle);
ap(pa, builder, handle);
};
(appender, checker)
}}
}
pub macro parse_form {
($appender_checker:expr, "",) => {{
use crate::private_exports::duat_core::{
context::Handle, data::Pass, file::File, form, text::Builder
};
let (appender, checker) = $appender_checker;
let appender = move |pa: &Pass, builder: &mut Builder, handle: &Handle<File<_>, _>| {
appender(pa, builder, handle);
builder.push(form::DEFAULT_ID);
};
(appender, checker)
}},
($appender_checker:expr, "", $($form:tt)*) => {{
use crate::private_exports::duat_core::{
context::Handle, data::Pass, file::File, form, text::Builder
};
let (appender, checker) = $appender_checker;
let id = form::id_of!(concat!($(stringify!($form)),*));
let appender = move |pa: &Pass, builder: &mut Builder, handle: &Handle<File<_>, _>| {
appender(pa, builder, handle);
builder.push(id);
};
(appender, checker)
}},
($pre_fn_and_checker:expr, $modif:literal, $($form:ident).*) => {{
compile_error!(concat!(
"at the moment, Forms in StatusLines don't support modifiers like ",
$modif
))
}}
}
}