@@ -490,6 +490,172 @@ impl<T: Item + 'static> FilePicker<T> {
492 fn render_picker(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
492 fn render_picker(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
493+ let text_style = cx.editor.theme.get("ui.text");
494+ let selected = cx.editor.theme.get("ui.text.focus");
495+ let highlight_style = cx.editor.theme.get("special").add_modifier(Modifier::BOLD);
497+ // -- Render the frame:
499+ let background = cx.editor.theme.get("ui.background");
500+ surface.clear_with(area, background);
502+ // don't like this but the lifetime sucks
503+ let block = Block::default().borders(Borders::ALL);
505+ // calculate the inner area inside the box
506+ let inner = block.inner(area);
508+ block.render(area, surface);
510+ // -- Render the input bar:
512+ let area = inner.clip_left(1).with_height(1);
514+ let count = format!("{}/{}", self.matches.len(), self.options.len());
515+ surface.set_stringn(
516+ (area.x + area.width).saturating_sub(count.len() as u16 + 1),
519+ (count.len()).min(area.width as usize),
523+ self.prompt.render(area, surface, cx);
526+ let sep_style = cx.editor.theme.get("ui.background.separator");
527+ let borders = BorderType::line_symbols(BorderType::Plain);
528+ for x in inner.left()..inner.right() {
529+ if let Some(cell) = surface.get_mut(x, inner.y + 1) {
530+ cell.set_symbol(borders.horizontal).set_style(sep_style);
534+ // -- Render the contents:
535+ // subtract area of prompt from top
536+ let inner = inner.clip_top(2);
538+ let rows = inner.height;
539+ let offset = self.cursor - (self.cursor % std::cmp::max(1, rows as usize));
540+ let cursor = self.cursor.saturating_sub(offset);
546+ .take(rows as usize)
547+ .map(|pmatch| &self.options[pmatch.index])
548+ .map(|option| option.format(&self.editor_data))
550+ const TEMP_CELL_SEP: &str = " ";
552+ let line = row.cell_text().fold(String::new(), |mut s, frag| {
554+ s.push_str(TEMP_CELL_SEP);
558+ // Items are filtered by using the text returned by menu::Item::filter_text
559+ // but we do highlighting here using the text in Row and therefore there
560+ // might be inconsistencies. This is the best we can do since only the
561+ // text in Row is displayed to the end user.
562+ let (_score, highlights) = FuzzyQuery::new(self.prompt.line())
563+ .fuzzy_indices(&line, &self.matcher)
564+ .unwrap_or_default();
566+ let highlight_byte_ranges: Vec<_> = line
569+ .filter_map(|(char_idx, (byte_offset, ch))| {
571+ .contains(&char_idx)
572+ .then(|| byte_offset..byte_offset + ch.len_utf8())
576+ // The starting byte index of the current (iterating) cell
577+ let mut cell_start_byte_offset = 0;
578+ for cell in row.cells.iter_mut() {
579+ let spans = match cell.content.lines.get(0) {
582+ cell_start_byte_offset += TEMP_CELL_SEP.len();
587+ let mut cell_len = 0;
589+ let graphemes_with_style: Vec<_> = spans
594+ .grapheme_indices(true)
595+ .zip(std::iter::repeat(span.style))
597+ .map(|((grapheme_byte_offset, grapheme), style)| {
598+ cell_len += grapheme.len();
599+ let start = cell_start_byte_offset;
601+ let grapheme_byte_range =
602+ grapheme_byte_offset..grapheme_byte_offset + grapheme.len();
604+ if highlight_byte_ranges.iter().any(|hl_rng| {
605+ hl_rng.start >= start + grapheme_byte_range.start
606+ && hl_rng.end <= start + grapheme_byte_range.end
608+ (grapheme, style.patch(highlight_style))
615+ let mut span_list: Vec<(String, Style)> = Vec::new();
616+ for (grapheme, style) in graphemes_with_style {
617+ if span_list.last().map(|(_, sty)| sty) == Some(&style) {
618+ let (string, _) = span_list.last_mut().unwrap();
619+ string.push_str(grapheme);
621+ span_list.push((String::from(grapheme), style))
625+ let spans: Vec<Span> = span_list
627+ .map(|(string, style)| Span::styled(string, style))
629+ let spans: Spans = spans.into();
630+ *cell = Cell::from(spans);
632+ cell_start_byte_offset += cell_len + TEMP_CELL_SEP.len();
638+ let table = Table::new(options)
640+ .highlight_style(selected)
641+ .highlight_symbol(" > ")
643+ .widths(&self.widths);
645+ use tui::widgets::TableState;
652+ selected: Some(cursor),
654+ self.truncate_start,
658+ fn render_preview(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
493 // +---------+ +---------+
659 // +---------+ +---------+
494 // |prompt | |preview |
660 // |prompt | |preview |
495 // +---------+ | |
661 // +---------+ | |
@@ -836,169 +1002,7 @@ impl<T: Item + 'static> Component for Picker<T> {
838 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
1004 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
839− let text_style = cx.editor.theme.get("ui.text");
1005+ unimplemented!()
840− let selected = cx.editor.theme.get("ui.text.focus");
841− let highlight_style = cx.editor.theme.get("special").add_modifier(Modifier::BOLD);
843− // -- Render the frame:
845− let background = cx.editor.theme.get("ui.background");
846− surface.clear_with(area, background);
848− // don't like this but the lifetime sucks
849− let block = Block::default().borders(Borders::ALL);
851− // calculate the inner area inside the box
852− let inner = block.inner(area);
854− block.render(area, surface);
856− // -- Render the input bar:
858− let area = inner.clip_left(1).with_height(1);
860− let count = format!("{}/{}", self.matches.len(), self.options.len());
861− surface.set_stringn(
862− (area.x + area.width).saturating_sub(count.len() as u16 + 1),
865− (count.len()).min(area.width as usize),
869− self.prompt.render(area, surface, cx);
872− let sep_style = cx.editor.theme.get("ui.background.separator");
873− let borders = BorderType::line_symbols(BorderType::Plain);
874− for x in inner.left()..inner.right() {
875− if let Some(cell) = surface.get_mut(x, inner.y + 1) {
876− cell.set_symbol(borders.horizontal).set_style(sep_style);
880− // -- Render the contents:
881− // subtract area of prompt from top
882− let inner = inner.clip_top(2);
884− let rows = inner.height;
885− let offset = self.cursor - (self.cursor % std::cmp::max(1, rows as usize));
886− let cursor = self.cursor.saturating_sub(offset);
892− .take(rows as usize)
893− .map(|pmatch| &self.options[pmatch.index])
894− .map(|option| option.format(&self.editor_data))
896− const TEMP_CELL_SEP: &str = " ";
898− let line = row.cell_text().fold(String::new(), |mut s, frag| {
900− s.push_str(TEMP_CELL_SEP);
904− // Items are filtered by using the text returned by menu::Item::filter_text
905− // but we do highlighting here using the text in Row and therefore there
906− // might be inconsistencies. This is the best we can do since only the
907− // text in Row is displayed to the end user.
908− let (_score, highlights) = FuzzyQuery::new(self.prompt.line())
909− .fuzzy_indices(&line, &self.matcher)
910− .unwrap_or_default();
912− let highlight_byte_ranges: Vec<_> = line
915− .filter_map(|(char_idx, (byte_offset, ch))| {
917− .contains(&char_idx)
918− .then(|| byte_offset..byte_offset + ch.len_utf8())
922− // The starting byte index of the current (iterating) cell
923− let mut cell_start_byte_offset = 0;
924− for cell in row.cells.iter_mut() {
925− let spans = match cell.content.lines.get(0) {
928− cell_start_byte_offset += TEMP_CELL_SEP.len();
933− let mut cell_len = 0;
935− let graphemes_with_style: Vec<_> = spans
940− .grapheme_indices(true)
941− .zip(std::iter::repeat(span.style))
943− .map(|((grapheme_byte_offset, grapheme), style)| {
944− cell_len += grapheme.len();
945− let start = cell_start_byte_offset;
947− let grapheme_byte_range =
948− grapheme_byte_offset..grapheme_byte_offset + grapheme.len();
950− if highlight_byte_ranges.iter().any(|hl_rng| {
951− hl_rng.start >= start + grapheme_byte_range.start
952− && hl_rng.end <= start + grapheme_byte_range.end
954− (grapheme, style.patch(highlight_style))
961− let mut span_list: Vec<(String, Style)> = Vec::new();
962− for (grapheme, style) in graphemes_with_style {
963− if span_list.last().map(|(_, sty)| sty) == Some(&style) {
964− let (string, _) = span_list.last_mut().unwrap();
965− string.push_str(grapheme);
967− span_list.push((String::from(grapheme), style))
971− let spans: Vec<Span> = span_list
973− .map(|(string, style)| Span::styled(string, style))
975− let spans: Spans = spans.into();
976− *cell = Cell::from(spans);
978− cell_start_byte_offset += cell_len + TEMP_CELL_SEP.len();
984− let table = Table::new(options)
986− .highlight_style(selected)
987− .highlight_symbol(" > ")
989− .widths(&self.widths);
991− use tui::widgets::TableState;
998− selected: Some(cursor),
1000− self.truncate_start,
1004 fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1008 fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {