pub async fn search(
        &mut self,
        annotations: Vec<Annotation>,
        fuzzy: bool,
    ) -> color_eyre::Result<()> {
        let mut annotations = annotations;
        if self.config.annotation_template.is_none() {
            self.config.set_annotation_template()?;
        }
        let hbs = self.get_handlebars()?;
        let options = SkimOptionsBuilder::default()
            .height(Some("100%"))
            .preview(Some(""))
            .preview_window(Some("up:40%:wrap"))
            .bind(vec![
                "ctrl-a:select-all",
                "left:scroll-left",
                "right:scroll-right",
                "ctrl-c:abort",
                "shift-left:accept",
                "shift-right:accept",
                "shift-up:accept",
                "shift-down:accept",
                "Enter:accept"
            ])
            .exact(!fuzzy)
            .header(Some("Arrow keys to scroll, Tab to toggle selection, Ctrl-A to select all, Esc to abort\n\
            Enter to add a tag, Shift-Left to delete a tag, Shift-Right to delete annotation\n\
            Shift-Down to make knowledge-base files, Shift-Up to print the set of URIs"))
            .multi(true)
            .reverse(true)
            .build()
            .map_err(|_| Apologize::SearchError)?;

        let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded();
        for annotation in &annotations {
            let mut title = String::from("Untitled document");
            if let Some(document) = &annotation.document {
                if !document.title.is_empty() {
                    title = document.title[0].to_owned();
                }
            }
            let mut highlight = format!(
                "{}",
                style(title.replace("\n", " ")).fg(dialoguer::console::Color::Green)
            );
            let quote = utils::get_quotes(&annotation).join(" ").replace("\n", " ");
            if !quote.is_empty() {
                highlight.push_str(&format!("| {}", quote));
            }
            if !annotation.text.is_empty() {
                highlight.push_str(&format!("| {}", annotation.text.replace("\n", " ")));
            }
            if !annotation.tags.is_empty() {
                highlight.push_str(&format!(
                    "|{}",
                    style(&annotation.tags.join("|")).fg(dialoguer::console::Color::Red)
                ));
            }
            highlight.push_str(&format!(
                "| {}",
                style(&annotation.uri)
                    .fg(dialoguer::console::Color::Cyan)
                    .italic()
                    .underlined()
            ));
            let _ = tx_item.send(Arc::new(SearchAnnotation {
                highlight,
                markdown: hbs.render(
                    "annotation",
                    &AnnotationTemplate::from_annotation(annotation.clone()),
                )?,
                id: annotation.id.to_owned(),
            }));
        }
        drop(tx_item); // so that skim could know when to stop waiting for more items.
        drop(hbs);
        if let Some(output) = Skim::run_with(&options, Some(rx_item)) {
            let annotation_ids: HashSet<String> = output
                .selected_items
                .into_iter()
                .map(|s| {
                    s.as_any()
                        .downcast_ref::<SearchAnnotation>()
                        .unwrap()
                        .id
                        .to_string()
                })
                .collect();
            annotations = annotations
                .into_iter()
                .filter(|a| annotation_ids.contains(&a.id))
                .collect();
            if annotations.is_empty() {
                println!("Nothing selected");
                return Ok(());
            }
            let key = output.final_key;
            match key {
                Key::Enter => {
                    let tags = self.search_tags(&annotations, true)?;
                    self.tag(annotations, false, Some(tags)).await?;
                }
                Key::ShiftLeft => {
                    let tags = self.search_tags(&annotations, false)?;
                    self.tag(annotations, true, Some(tags)).await?;
                }
                Key::ShiftRight => {
                    self.delete(annotations, false).await?;
                }
                Key::ShiftDown => {
                    let clear = Confirm::with_theme(&ColorfulTheme::default())
                        .with_prompt("Clear knowledge base directory?")
                        .default(true)
                        .interact()?;
                    let index = Confirm::with_theme(&ColorfulTheme::default())
                        .with_prompt("Also make index file?")
                        .default(true)
                        .interact()?;
                    self.make(annotations, clear, true, true, index).await?;
                }
                Key::ShiftUp => {
                    self.uri(annotations, Vec::new())?;
                }
                _ => (),
            }
            Ok(())
        } else {
            Err(Apologize::SearchError.into())
        }
    }
/// Makes a skim search window for given annotations
Makes a skim search window for given annotations
Makes a skim search window for given annotations
pub async fn search(
        &mut self,
        annotations: Vec<Annotation>,
        fuzzy: bool,
    ) -> color_eyre::Result<()> {
        let mut annotations = annotations;
        if self.config.annotation_template.is_none() {
            self.config.set_annotation_template()?;
        }
        let hbs = self.get_handlebars()?;
        let options = SkimOptionsBuilder::default()
            .height(Some("100%"))
            .preview(Some(""))
            .preview_window(Some("up:40%:wrap"))
            .bind(vec![
                "ctrl-a:select-all",
                "left:scroll-left",
                "right:scroll-right",
                "ctrl-c:abort",
                "shift-left:accept",
                "shift-right:accept",
                "shift-up:accept",
                "shift-down:accept",
                "Enter:accept"
            ])
            .exact(!fuzzy)
            .header(Some("Arrow keys to scroll, Tab to toggle selection, Ctrl-A to select all, Esc to abort\n\
            Enter to add a tag, Shift-Left to delete a tag, Shift-Right to delete annotation\n\
            Shift-Down to make knowledge-base files, Shift-Up to print the set of URIs"))
            .multi(true)
            .reverse(true)
            .build()
            .map_err(|_| Apologize::SearchError)?;
        let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded();
        for annotation in &annotations {
            let mut title = String::from("Untitled document");
            if let Some(document) = &annotation.document {
                if !document.title.is_empty() {
                    title = document.title[0].to_owned();
                }
            }
            let mut highlight = format!(
                "{}",
                style(title.replace("\n", " ")).fg(dialoguer::console::Color::Green)
            );
            let quote = utils::get_quotes(&annotation).join(" ").replace("\n", " ");
            if !quote.is_empty() {
                highlight.push_str(&format!("| {}", quote));
            }
            if !annotation.text.is_empty() {
                highlight.push_str(&format!("| {}", annotation.text.replace("\n", " ")));
            }
            if !annotation.tags.is_empty() {
                highlight.push_str(&format!(
                    "|{}",
                    style(&annotation.tags.join("|")).fg(dialoguer::console::Color::Red)
                ));
            }
            highlight.push_str(&format!(
                "| {}",
                style(&annotation.uri)
                    .fg(dialoguer::console::Color::Cyan)
                    .italic()
                    .underlined()
            ));
            let _ = tx_item.send(Arc::new(SearchAnnotation {
                highlight,
                markdown: hbs.render(
                    "annotation",
                    &AnnotationTemplate::from_annotation(annotation.clone()),
                )?,
                id: annotation.id.to_owned(),
            }));
        }
        drop(tx_item); // so that skim could know when to stop waiting for more items.
        drop(hbs);
        if let Some(output) = Skim::run_with(&options, Some(rx_item)) {
            let annotation_ids: HashSet<String> = output
                .selected_items
                .into_iter()
                .map(|s| {
                    s.as_any()
                        .downcast_ref::<SearchAnnotation>()
                        .unwrap()
                        .id
                        .to_string()
                })
                .collect();
            annotations = annotations
                .into_iter()
                .filter(|a| annotation_ids.contains(&a.id))
                .collect();
            if annotations.is_empty() {
                println!("Nothing selected");
                return Ok(());
            }
            let key = output.final_key;
            match key {
                Key::Enter => {
                    let tags = self.search_tags(&annotations, true)?;
                    self.tag(annotations, false, Some(tags)).await?;
                }
                Key::ShiftLeft => {
                    let tags = self.search_tags(&annotations, false)?;
                    self.tag(annotations, true, Some(tags)).await?;
                }
                Key::ShiftRight => {
                    self.delete(annotations, false).await?;
                }
                Key::ShiftDown => {
                    let clear = Confirm::with_theme(&ColorfulTheme::default())
                        .with_prompt("Clear knowledge base directory?")
                        .default(true)
                        .interact()?;
                    let index = Confirm::with_theme(&ColorfulTheme::default())
                        .with_prompt("Also make index file?")
                        .default(true)
                        .interact()?;
                    self.make(annotations, clear, true, true, index).await?;
                }
                Key::ShiftUp => {
                    self.uri(annotations, Vec::new())?;
                }
                _ => (),
            }
            Ok(())
        } else {
            Err(Apologize::SearchError.into())
        }
    }
pub async fn search ( & mut self , annotations : Vec < Annotation > , fuzzy : bool , ) -> color_eyre :: Result < ( ) > { let mut annotations = annotations ; if self . config . annotation_template . is_none ( ) { self . config . set_annotation_template ( ) ? ; } let hbs = self . get_handlebars ( ) ? ; let options = SkimOptionsBuilder :: default ( ) . height ( Some ( " " ) ) . preview ( Some ( " " ) ) . preview_window ( Some ( " " ) ) . bind ( vec ! [ " " " " " " " " " " " " " " " " " " ] ) . exact ( ! fuzzy ) . header ( Some ( " \n \
 \n \
 " ) ) . multi ( true ) . reverse ( true ) . build ( ) . map_err ( | _ | Apologize :: SearchError ) ? ; let ( tx_item , rx_item ) : ( SkimItemSender , SkimItemReceiver ) = unbounded ( ) ; for annotation in & annotations { let mut title = String :: from ( " " ) ; if let Some ( document ) = & annotation . document { if ! document . title . is_empty ( ) { title = document . title [ 0 ] . to_owned ( ) ; } } let mut highlight = format ! ( " " style ( title replace ( " \n " " " ) ) fg ( dialoguer console Color Green ) ) ; let quote = utils :: get_quotes ( & annotation ) . join ( " " ) . replace ( " \n " , " " ) ; if ! quote . is_empty ( ) { highlight . push_str ( & format ! ( " " quote ) ) ; } if ! annotation . text . is_empty ( ) { highlight . push_str ( & format ! ( " " annotation text replace ( " \n " " " ) ) ) ; } if ! annotation . tags . is_empty ( ) { highlight . push_str ( & format ! ( " " style ( annotation tags join ( " " ) ) fg ( dialoguer console Color Red ) ) ) ; } highlight . push_str ( & format ! ( " " style ( annotation uri ) fg ( dialoguer console Color Cyan ) italic ( ) underlined ( ) ) ) ; let _ = tx_item . send ( Arc :: new ( SearchAnnotation { highlight , markdown : hbs . render ( " " , & AnnotationTemplate :: from_annotation ( annotation . clone ( ) ) , ) ? , id : annotation . id . to_owned ( ) , } ) ) ; } drop ( tx_item ) ; // so that skim could know when to stop waiting for more items. drop ( hbs ) ; if let Some ( output ) = Skim :: run_with ( & options , Some ( rx_item ) ) { let annotation_ids : HashSet < String > = output . selected_items . into_iter ( ) . map ( | s | { s . as_any ( ) . downcast_ref :: < SearchAnnotation > ( ) . unwrap ( ) . id . to_string ( ) } ) . collect ( ) ; annotations = annotations . into_iter ( ) . filter ( | a | annotation_ids . contains ( & a . id ) ) . collect ( ) ; if annotations . is_empty ( ) { println ! ( " " ) ; return Ok ( ( ) ) ; } let key = output . final_key ; match key { Key :: Enter => { let tags = self . search_tags ( & annotations , true ) ? ; self . tag ( annotations , false , Some ( tags ) ) . await ? ; } Key :: ShiftLeft => { let tags = self . search_tags ( & annotations , false ) ? ; self . tag ( annotations , true , Some ( tags ) ) . await ? ; } Key :: ShiftRight => { self . delete ( annotations , false ) . await ? ; } Key :: ShiftDown => { let clear = Confirm :: with_theme ( & ColorfulTheme :: default ( ) ) . with_prompt ( " " ) . default ( true ) . interact ( ) ? ; let index = Confirm :: with_theme ( & ColorfulTheme :: default ( ) ) . with_prompt ( " " ) . default ( true ) . interact ( ) ? ; self . make ( annotations , clear , true , true , index ) . await ? ; } Key :: ShiftUp => { self . uri ( annotations , Vec :: new ( ) ) ? ; } _ => ( ) , } Ok ( ( ) ) } else { Err ( Apologize :: SearchError . into ( ) ) } }
Makes a skim search window for given annotations
Makes a skim search window for given annotations
&mut self
annotations
Vec<Annotation>
fuzzy
bool
&mut self
annotations
Vec<Annotation>
fuzzy
bool