NAME
Term::Fabulous::Role::Searchable - The texts of a widget, for search and highlights
SYNOPSIS
use Term::Fabulous::Role::Searchable qw(searchables_in);
foreach my $widget ( searchables_in($item) ) {
foreach my $entry ( $widget->search_texts ) {
my ( $key, $text ) = @$entry;
next unless $text =~ /needle/;
$widget->highlight_text( $key, [ [ $-[0], $+[0], 'on yellow' ] ] );
my ( $shown, $row ) = @{ $widget->reveal_text( $key, $-[0] ) };
}
}
DESCRIPTION
A widget that composes this role can be searched: it says which texts it shows, marks ranges of a text with a style, and brings a text into view inside itself. Term::Fabulous::Widget::Text and Term::Fabulous::Widget::CodeBlock do it for the one text each of them holds. A widget that builds its texts only when it needs them, such as a table with cells on other pages, does it from its own data, so that a search reaches text that is not on the screen. Term::Fabulous::Widget::DocumentView searches its items through this role. "Search a document and show the reader's position (search, ViewChange)" in Term::Fabulous::Cookbook::Documents shows a search over a document; "Widgets a search finds" in Term::Fabulous::Manual::CustomWidgets shows how to make a widget of your own searchable.
The role declares the methods below, which a class that composes it defines, and provides "search_serial". A widget that holds other searchable widgets and answers for them composes Term::Fabulous::Role::SearchContainer instead, which provides the methods.
A key names one text of the widget (see "search_texts"). Keys are only valid together with their revision: a caller that keeps a key (a search that remembers its matches) keeps the "search_revision" it read with it, and compares the two before it uses the key again; when the revision differs, the text changed and the caller searches again.
REQUIRED METHODS
search_texts
my @entries = $widget->search_texts; # ( [ $key, $text ], ... )
The texts the widget shows, in the order they appear, each with a key: any value that names that text within the widget and stays the same while the text exists, such as undef for a widget with one text, or a row and a column for a table cell. Offsets into $text are character offsets.
search_revision
my $revision = $widget->search_revision($key);
A value that changes whenever the text named by the key changes, so a caller can tell whether offsets it recorded earlier still point where they did. Comparing two values with ne is enough.
highlight_text
$widget->highlight_text( $key, [ [ $start, $end, $style ], ... ] );
Marks ranges of the text named by the key with styles (strings or hash references as Term::Fabulous::Text::Style reads them), replacing the ranges given before for that text. The widget shows them over its own styles whenever it shows that text, also when it builds the widget for it later. Offsets past the text die.
clear_text_highlights
$widget->clear_text_highlights;
Removes every highlight of every text of the widget.
reveal_text
my ( $shown, $row ) = @{ $widget->reveal_text( $key, $offset ) };
Makes the text named by the key visible inside the widget, as far as the widget can: a table turns to the page of the row, a tab control activates the page. Returns an array reference of two values, each of which may be undef: the widget that shows the text (a Text inside the widget, such as a table's cell, or the widget itself, as a Text or a CodeBlock returns), once it exists, and the row within the widget on which the character at the offset lies, when the widget knows it before a layout (a code block knows its line). A caller that scrolls the widget into view uses the row, else the text widget's painted lines, else the widget's own box.
PROVIDED METHODS
search_serial
my $serial = $widget->search_serial;
A number that names the widget among all searchable widgets made by the process, given at construction and never reused, also not after the widget is freed. "nested_search_revision" puts it into the revisions of the texts a container answers for, so that a key that leads to another widget after the widgets changed reads as changed.
FUNCTIONS
searchables_in
my @widgets = searchables_in($widget);
The widgets at or below $widget that compose this role, in layout order: $widget itself if it does, else those found among its layout children, the children of a widget that does the role not included (it answers for them). Exported on request.
Nested keys
The functions below are the role's methods for a widget that answers for searchable widgets inside it (its parts): \@widgets are those widgets (from "searchables_in"), and a key names one by its index in the list and that widget's own key, [ $index, $key ]. Keys are positions, so a key still means "the same place" after its widget was built again (a table re-applies highlights to rebuilt cells by position). A key whose index is past the list names no widget; a key that is not [ index, key ] dies. Term::Fabulous::Role::SearchContainer provides the role's methods with them, for Term::Fabulous::Widget::Tabs and Term::Fabulous::Widget::Accordion::Item; Term::Fabulous::Widget::Table calls them for the widgets of its custom cells. All exported on request.
nested_part
my $widget = nested_part( \@widgets, $key );
The widget the key names, or undef when its index is past the list.
nested_search_texts
my @entries = nested_search_texts( \@widgets ); # keys [ $index, $key ]
The texts of all the widgets, in order, with nested keys.
nested_search_revision
my $revision = nested_search_revision( \@widgets, $key );
The "search_serial" of the widget at the index and that widget's own revision of the text, "$serial:$revision": when another widget comes to the index (a page was removed before it), the revision changes, so a caller that compares revisions searches again instead of using the key. 'gone' for a key whose index is past the list.
nested_highlight_text
nested_highlight_text( \@widgets, $key, \@ranges );
Highlights the text in the widget the key names; nothing for a key past the list.
nested_clear_text_highlights
nested_clear_text_highlights( \@widgets );
Clears the highlights of every widget.
nested_reveal_text
my $revealed = nested_reveal_text( \@widgets, $key, $offset );
The widget's reveal_text; [ undef, undef ] for a key past the list.
SEE ALSO
Term::Fabulous::Role::SearchContainer, Term::Fabulous::Role::MarkedText, Term::Fabulous::Widget::Text, Term::Fabulous::Widget::CodeBlock, Term::Fabulous::Widget::Table, Term::Fabulous::Widget::Tabs, Term::Fabulous::Widget::Accordion::Item, Term::Fabulous::Widget::DocumentView, "Widgets a search finds" in Term::Fabulous::Manual::CustomWidgets.