Skip to main content

diffs_rs/engine/
reading.rs

1use super::*;
2use crate::reading::{SearchMatch, SearchRead, SearchStart, literal, search::Position};
3
4impl Engine {
5    /// Captures diff text and the current reading origin. It does not start a worker.
6    /// The caller owns cancellation/join and must reject superseded query replies.
7    pub fn search_read(&mut self, query: String) -> Result<SearchRead> {
8        literal::validate(&query)?;
9        let selected = self.selected_source()?;
10        let domain = self.search_domain()?;
11        let app = self
12            .app
13            .as_ref()
14            .context("Review source is not available")?;
15        let preferred = selected
16            .map_or(if app.old_side { Side::Old } else { Side::New }, |source| {
17                source.side
18            });
19        let start = if let Some(row) = app.row(app.cursor.row) {
20            if let (Some(selected), RowKind::Code { left, right }) = (selected, row.kind) {
21                let source = if selected.side == Side::Old {
22                    left
23                } else {
24                    right
25                }
26                .context("Selected search source is not available")?;
27                SearchStart::At(Position {
28                    file: row.file,
29                    row: domain.files[row.file]
30                        .order
31                        .row_for_source(source)
32                        .context("Selected source is outside search scope")?,
33                    byte: 0,
34                })
35            } else {
36                SearchStart::AfterRow {
37                    display: app
38                        .view
39                        .reading_order(app.doc.files[row.file].clone(), app.split()),
40                    row: app.cursor.row - app.view.file_row(&app.doc, row.file, app.split()),
41                }
42            }
43        } else {
44            SearchStart::At(Position::default())
45        };
46        SearchRead::new(domain, query, start, preferred)
47    }
48
49    /// Selects a validated match without accepting another query's late reply for the caller.
50    pub fn show_search_match(&mut self, found: &SearchMatch) -> Result<()> {
51        found.check(self.id)?;
52        let app = self.app.as_mut().context("The review is closed")?;
53        app.reveal_source(
54            found.hit.source,
55            found.display.start,
56            found.location().side == Side::Old,
57        )?;
58        app.search_match = Some(found.clone());
59        self.changed(InputEffect::Highlight);
60        self.track_selection(true)?;
61        Ok(())
62    }
63
64    pub fn clear_search_match(&mut self) {
65        if let Some(app) = &mut self.app
66            && app.search_match.take().is_some()
67        {
68            self.changed(InputEffect::Redraw);
69        }
70    }
71}