1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! Snapshot, scrollback, and pattern search.
#[cfg(feature = "async")]
use std::sync::Arc;
use super::Session;
use crate::snapshot::{
inspect_snapshot_from_screen, scrollback_snapshot_from_screen, snapshot_from_screen,
};
use crate::{InspectSnapshot, ScrollbackSnapshot, Snapshot};
impl Session {
/// Return a rich snapshot of the current terminal state.
#[must_use]
pub fn snapshot(&self) -> Snapshot {
self.terminal.with_screen(snapshot_from_screen)
}
/// Search the viewport (and optionally scrollback) for matches of
/// `pattern`.
///
/// Soft-wrapped physical rows are joined into one logical line
/// before matching, so a regex like `WARN.*failed` finds a hit
/// even if the renderer overflowed the right edge in the middle
/// of `WARN`. Regex anchors operate on logical lines: `^` matches
/// the first column, `$` matches the last, and `\n` in the
/// pattern crosses a logical-line boundary.
///
/// Match positions count cells, not bytes: a wide character
/// (CJK, emoji, ...) sits in one cell whose column is the
/// lead-half cell's column, so the
/// [`AbsolutePosition`](tastty::AbsolutePosition) in a returned
/// [`SearchMatch`](crate::SearchMatch) is directly comparable
/// with [`Screen::visible_to_absolute`](tastty::Screen::visible_to_absolute)
/// output and with [`WaitMatch::position`](crate::WaitMatch).
///
/// Holds the parser read lock for the duration of the walk; for
/// long-running searches over deep scrollback consider capping
/// with [`SearchOptions::max_results`](crate::SearchOptions::max_results)
/// so write-side updates (input echo, child output) are not
/// blocked unnecessarily.
///
/// # Errors
///
/// Returns [`SearchError::EmptyPattern`](crate::SearchError::EmptyPattern)
/// when called with an empty
/// [`SearchPattern::Literal`](crate::SearchPattern::Literal);
/// regex emptiness is rejected at construction time by
/// [`SearchPattern::regex`](crate::SearchPattern::regex).
pub fn find(
&self,
pattern: &crate::SearchPattern,
opts: crate::SearchOptions,
) -> std::result::Result<Vec<crate::SearchMatch>, crate::SearchError> {
self.terminal
.with_screen(|screen| crate::search::find(screen, pattern, opts))
}
/// Asynchronous variant of [`Session::find`].
///
/// Cancellation-safe: dropping the returned future before it
/// resolves leaves no parser-state poisoning, and reissuing on the
/// same [`Session`] is always safe. Returns a `Send + 'static`
/// future so it can be spawned on any executor; pattern ownership
/// is taken by value (the compiled regex is reference-counted, so
/// callers reusing a pattern just clone it).
///
/// See [`Session::find`] for pattern semantics, anchor and column
/// rules, scrollback and direction options, and the error path.
///
/// # Errors
///
/// Same as [`Session::find`].
#[cfg(feature = "async")]
pub fn find_async(
&self,
pattern: crate::SearchPattern,
opts: crate::SearchOptions,
) -> impl std::future::Future<
Output = std::result::Result<Vec<crate::SearchMatch>, crate::SearchError>,
> + Send
+ 'static {
let terminal = Arc::clone(&self.terminal);
async move { terminal.with_screen(|screen| crate::search::find(screen, &pattern, opts)) }
}
/// Return retained scrollback rows followed by visible screen rows.
#[must_use]
pub fn snapshot_with_scrollback(&self, limit: Option<usize>) -> ScrollbackSnapshot {
self.terminal
.with_screen(|screen| scrollback_snapshot_from_screen(screen, limit))
}
/// Return the number of retained scrollback rows available.
#[must_use]
pub fn scrollback_count(&self) -> usize {
self.terminal
.with_screen(|screen| screen.scrollback_available())
}
/// Return terminal mode and metadata state.
#[must_use]
pub fn inspect(&self) -> InspectSnapshot {
self.terminal.with_screen(inspect_snapshot_from_screen)
}
}