1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-09-03 14:26:17 +03:00

add tests and document for text search

Этот коммит содержится в:
rhysd
2022-07-08 11:59:59 +09:00
родитель 86bd8dd6ef
Коммит 8320fcdbb8
3 изменённых файлов: 143 добавлений и 4 удалений

4
.github/workflows/ci.yml поставляемый
Просмотреть файл

@@ -18,9 +18,9 @@ jobs:
toolchain: stable
override: true
- uses: Swatinem/rust-cache@v1
- run: cargo test -- --skip src/lib.rs
- run: cargo test --all-features -- --skip src/lib.rs
if: ${{ matrix.os != 'windows-latest' }}
- run: cargo test -- --skip src\lib.rs
- run: cargo test --all-features -- --skip src\lib.rs
if: ${{ matrix.os == 'windows-latest' }}
lint:
runs-on: ubuntu-latest

Просмотреть файл

@@ -70,7 +70,7 @@ impl<'a> SearchBox<'a> {
key: Key::Char('m'),
ctrl: true,
..
} => None,
} => None, // Disable shortcuts which inserts a newline. See `single_line` example
input => {
let modified = self.textarea.input(input);
modified.then(|| self.textarea.lines()[0].as_str())

Просмотреть файл

@@ -1418,6 +1418,35 @@ impl<'a> TextArea<'a> {
self.yank = text.into();
}
/// Set a regular expression pattern for text search. Setting an empty string stops the text search.
/// When a valid pattern is set, all matches will be highlighted in the textarea. Note that the cursor does not
/// move. To move the cursor, use [`TextArea::search_forward`] and [`TextArea::search_back`].
///
/// Grammar of regular expression follows [regex crate](https://docs.rs/regex/latest/regex). Patterns don't match
/// to newlines so match passes across no newline.
///
/// When the pattern is invalid, the search pattern will not be updated and an error will be returned.
///
/// ```
/// use tui_textarea::TextArea;
///
/// let mut textarea = TextArea::from(["hello, world", "goodbye, world"]);
///
/// // Search "world"
/// textarea.set_search_pattern("world").unwrap();
///
/// assert_eq!(textarea.cursor(), (0, 0));
/// textarea.search_forward(false);
/// assert_eq!(textarea.cursor(), (0, 7));
/// textarea.search_forward(false);
/// assert_eq!(textarea.cursor(), (1, 9));
///
/// // Stop the text search
/// textarea.set_search_pattern("");
///
/// // Invalid search pattern
/// assert!(textarea.set_search_pattern("(hello").is_err());
/// ```
#[cfg(feature = "search")]
pub fn set_search_pattern(&mut self, query: impl AsRef<str>) -> Result<(), regex::Error> {
let query = query.as_ref();
@@ -1429,6 +1458,61 @@ impl<'a> TextArea<'a> {
Ok(())
}
/// Get a regular expression which was set by [`TextArea::set_search_pattern`]. When no text search is ongoing, this
/// method returns `None`.
///
/// ```
/// use tui_textarea::TextArea;
///
/// let mut textarea = TextArea::default();
///
/// assert!(textarea.search_pattern().is_none());
/// textarea.set_search_pattern("hello+").unwrap();
/// assert!(textarea.search_pattern().is_some());
/// assert_eq!(textarea.search_pattern().unwrap().as_str(), "hello+");
/// ```
#[cfg(feature = "search")]
pub fn search_pattern(&self) -> Option<&Regex> {
self.search_pat.as_ref()
}
/// Search the pattern set by [`TextArea::set_search_pattern`] forward and move the cursor to the next match
/// position based on the current cursor position. Text search wraps around a text buffer. It returns `true` when
/// some match was found. Otherwise it returns `false`.
///
/// The `match_cursor` parameter represents if the search matches to the current cursor position or not. When `true`
/// is set and the cursor position matches to the pattern, the cursor will not move. When `false`, the cursor will
/// move to the next match ignoring the match at the current position.
///
/// ```
/// use tui_textarea::TextArea;
///
/// let mut textarea = TextArea::from(["hello", "helloo", "hellooo"]);
///
/// textarea.set_search_pattern("hello+").unwrap();
///
/// // Move to next position
/// let match_found = textarea.search_forward(false);
/// assert!(match_found);
/// assert_eq!(textarea.cursor(), (1, 0));
///
/// // Since the cursor position matches to "hello+", it does not move
/// textarea.search_forward(true);
/// assert_eq!(textarea.cursor(), (1, 0));
///
/// // When `match_current` parameter is set to `false`, match at the cursor position is ignored
/// textarea.search_forward(false);
/// assert_eq!(textarea.cursor(), (2, 0));
///
/// // Text search wrap around the buffer
/// textarea.search_forward(false);
/// assert_eq!(textarea.cursor(), (0, 0));
///
/// // `false` is returned when no match was found
/// textarea.set_search_pattern("bye+").unwrap();
/// let match_found = textarea.search_forward(false);
/// assert!(!match_found);
/// ```
#[cfg(feature = "search")]
pub fn search_forward(&mut self, match_cursor: bool) -> bool {
let pat = if let Some(pat) = &self.search_pat {
@@ -1485,6 +1569,39 @@ impl<'a> TextArea<'a> {
false
}
/// Search the pattern set by [`TextArea::set_search_pattern`] backward and move the cursor to the next match
/// position based on the current cursor position. Text search wraps around a text buffer. It returns `true` when
/// some match was found. Otherwise it returns `false`.
///
/// The `match_cursor` parameter represents if the search matches to the current cursor position or not. When `true`
/// is set and the cursor position matches to the pattern, the cursor will not move. When `false`, the cursor will
/// move to the next match ignoring the match at the current position.
///
/// ```
/// use tui_textarea::TextArea;
///
/// let mut textarea = TextArea::from(["hello", "helloo", "hellooo"]);
///
/// textarea.set_search_pattern("hello+").unwrap();
///
/// // Move to next position with wrapping around the text buffer
/// let match_found = textarea.search_back(false);
/// assert!(match_found);
/// assert_eq!(textarea.cursor(), (2, 0));
///
/// // Since the cursor position matches to "hello+", it does not move
/// textarea.search_back(true);
/// assert_eq!(textarea.cursor(), (2, 0));
///
/// // When `match_current` parameter is set to `false`, match at the cursor position is ignored
/// textarea.search_back(false);
/// assert_eq!(textarea.cursor(), (1, 0));
///
/// // `false` is returned when no match was found
/// textarea.set_search_pattern("bye+").unwrap();
/// let match_found = textarea.search_back(false);
/// assert!(!match_found);
/// ```
#[cfg(feature = "search")]
pub fn search_back(&mut self, match_cursor: bool) -> bool {
let pat = if let Some(pat) = &self.search_pat {
@@ -1496,7 +1613,7 @@ impl<'a> TextArea<'a> {
let current_line = &self.lines[row];
// Search current line before cursor
if col > 0 {
if col > 0 || match_cursor {
let start_col = if match_cursor { col } else { col - 1 };
if let Some((i, _)) = current_line.char_indices().nth(start_col) {
if let Some(m) = pat
@@ -1545,11 +1662,33 @@ impl<'a> TextArea<'a> {
false
}
/// Get the text style at matches of text search. The default style is colored with blue in background.
///
/// ```
/// use tui::style::{Style, Color};
/// use tui_textarea::TextArea;
///
/// let textarea = TextArea::default();
///
/// assert_eq!(textarea.search_style(), Style::default().bg(Color::Blue));
/// ```
#[cfg(feature = "search")]
pub fn search_style(&self) -> Style {
self.search_style
}
/// Set the text style at matches of text search. The default style is colored with blue in background.
/// ```
/// use tui::style::{Style, Color};
/// use tui_textarea::TextArea;
///
/// let mut textarea = TextArea::default();
///
/// let red_bg = Style::default().bg(Color::Red);
/// textarea.set_search_style(red_bg);
///
/// assert_eq!(textarea.search_style(), red_bg);
/// ```
#[cfg(feature = "search")]
pub fn set_search_style(&mut self, style: Style) {
self.search_style = style;