text_document/
operation.rs1use std::thread;
4use std::time::Duration;
5
6use anyhow::Result;
7
8use frontend::AppContext;
9
10pub(crate) struct OperationState {
12 ctx: AppContext,
13}
14
15impl OperationState {
16 pub fn new(ctx: &AppContext) -> Self {
17 Self { ctx: ctx.clone() }
18 }
19}
20
21pub struct Operation<T> {
31 id: String,
32 state: OperationState,
33 result_fn: Box<dyn Fn(&AppContext, &str) -> Option<Result<T>> + Send>,
34}
35
36impl<T> Operation<T> {
37 pub(crate) fn new(
38 id: String,
39 ctx: &AppContext,
40 result_fn: Box<dyn Fn(&AppContext, &str) -> Option<Result<T>> + Send>,
41 ) -> Self {
42 Self {
43 id,
44 state: OperationState::new(ctx),
45 result_fn,
46 }
47 }
48
49 pub fn id(&self) -> &str {
51 &self.id
52 }
53
54 pub fn progress(&self) -> Option<(f64, String)> {
57 let mgr = self
58 .state
59 .ctx
60 .long_operation_manager
61 .lock()
62 .ok()
63 .or_else(|| {
64 match self.state.ctx.long_operation_manager.lock() {
66 Ok(g) => Some(g),
67 Err(e) => Some(e.into_inner()),
68 }
69 })?;
70 mgr.get_operation_progress(&self.id)
71 .map(|p| (p.percentage as f64, p.message.unwrap_or_default()))
72 }
73
74 pub fn is_done(&self) -> bool {
76 (self.result_fn)(&self.state.ctx, &self.id).is_some()
77 }
78
79 pub fn cancel(&self) {
81 if let Ok(mgr) = self.state.ctx.long_operation_manager.lock() {
82 mgr.cancel_operation(&self.id);
83 }
84 }
85
86 pub fn wait(self) -> Result<T> {
89 loop {
90 if let Some(result) = (self.result_fn)(&self.state.ctx, &self.id) {
91 return result;
92 }
93 thread::sleep(Duration::from_millis(50));
94 }
95 }
96
97 pub fn wait_timeout(self, timeout: Duration) -> Option<Result<T>> {
100 let deadline = std::time::Instant::now() + timeout;
101 loop {
102 if let Some(result) = (self.result_fn)(&self.state.ctx, &self.id) {
103 return Some(result);
104 }
105 if std::time::Instant::now() >= deadline {
106 return None;
107 }
108 let remaining = deadline.saturating_duration_since(std::time::Instant::now());
109 thread::sleep(remaining.min(Duration::from_millis(50)));
110 }
111 }
112
113 pub fn try_result(&mut self) -> Option<Result<T>> {
116 (self.result_fn)(&self.state.ctx, &self.id)
117 }
118}
119
120#[derive(Debug, Clone)]
124pub struct MarkdownImportResult {
125 pub block_count: usize,
126}
127
128#[derive(Debug, Clone)]
130pub struct HtmlImportResult {
131 pub block_count: usize,
132}
133
134#[derive(Debug, Clone)]
136pub struct DocxExportResult {
137 pub file_path: String,
138 pub paragraph_count: usize,
139}