use frontend::AppContext;
use frontend::commands::{
document_commands, document_io_commands, document_search_commands, root_commands,
};
use frontend::common::parser_tools::{DjotExportOptions, DjotImportOptions};
use frontend::document::dtos::CreateDocumentDto;
use frontend::document_io::ImportDjotDto;
use frontend::root::dtos::CreateRootDto;
use crate::error::Result;
use crate::{FindMatch, FindOptions, ReplaceOptions, ReplaceRange};
pub struct BatchDocument {
ctx: AppContext,
}
impl BatchDocument {
pub fn new() -> Result<Self> {
let ctx = AppContext::new();
let root = root_commands::create_orphan_root(&ctx, &CreateRootDto::default())?;
document_commands::create_document(&ctx, None, &CreateDocumentDto::default(), root.id, -1)?;
Ok(Self { ctx })
}
pub fn set_djot(&self, djot: &str, options: &DjotImportOptions) -> Result<()> {
document_io_commands::import_djot_sync(
&self.ctx,
&ImportDjotDto {
djot_text: djot.to_string(),
options: *options,
},
)?;
Ok(())
}
pub fn to_djot(&self, options: &DjotExportOptions) -> Result<String> {
Ok(document_io_commands::export_djot(&self.ctx, options)?.djot_text)
}
pub fn find_all(&self, query: &str, options: &FindOptions) -> Result<Vec<FindMatch>> {
let result =
document_search_commands::find_all(&self.ctx, &options.to_find_all_dto(query))?;
Ok(crate::convert::find_all_to_matches(&result))
}
pub fn find_and_replace(
&self,
query: &str,
options: &ReplaceOptions,
mut decide: impl FnMut(&str, usize) -> Option<String>,
) -> Result<usize> {
let found =
document_search_commands::find_all(&self.ctx, &options.find.to_find_all_dto(query))?;
let mut ranges: Vec<ReplaceRange> = Vec::new();
for (i, ((&position, &length), matched)) in found
.positions
.iter()
.zip(found.lengths.iter())
.zip(found.matched_texts.iter())
.enumerate()
{
if let Some(replacement) = decide(matched, i) {
ranges.push(ReplaceRange {
position: position as usize,
length: length as usize,
replacement,
});
}
}
if ranges.is_empty() {
return Ok(0);
}
self.replace_ranges(&ranges, options)
}
pub fn replace_ranges(
&self,
ranges: &[ReplaceRange],
options: &ReplaceOptions,
) -> Result<usize> {
let result = document_search_commands::replace_ranges(
&self.ctx,
None,
&options.to_replace_ranges_dto(ranges),
)?;
Ok(result.replacements_count.max(0) as usize)
}
}