nkxxll bbbdcb0271
feat(cli): add substring matching with --exact flag (#477)
fixes #368 

@alexpasmantier I tried to parse down the exact flag to the find method,
but I can't find an elegant way to do so because the channel creates its
own configurations for the matcher inside of the `new` method. I started
adding the exact flag to the new function of each of the channels but it
just does not seem right to do so. Do you have an idea on how to improve
the change? I would think of passing the config struct to the new
function and exposing the config of the channel for channel transitions,
but I'm not sure... 🤔

I have done it here for the stdin channel just to show you how it would
look like and it works fine😄! Looking forward to hearing your thoughts
on that 👍

ref issue: #368

---------

Co-authored-by: Alexandre Pasmantier <alex.pasmant@gmail.com>
2025-04-22 00:37:07 +02:00

545 lines
18 KiB
Rust

use criterion::criterion_group;
use criterion::{black_box, Criterion};
use devicons::FileIcon;
use ratatui::backend::TestBackend;
use ratatui::layout::Alignment;
use ratatui::layout::Rect;
use ratatui::prelude::{Line, Style};
use ratatui::style::Color;
use ratatui::widgets::{Block, BorderType, Borders, ListDirection, Padding};
use ratatui::Terminal;
use std::path::PathBuf;
use television::action::Action;
use television::channels::entry::into_ranges;
use television::channels::entry::{Entry, PreviewType};
use television::channels::OnAir;
use television::channels::{files::Channel, TelevisionChannel};
use television::config::{Config, ConfigEnv};
use television::screen::colors::ResultsColorscheme;
use television::screen::results::build_results_list;
use television::television::Television;
use tokio::runtime::Runtime;
pub fn draw_results_list(c: &mut Criterion) {
// FIXME: there's probably a way to have this as a benchmark asset
// possible as a JSON file and to load it for the benchmark using Serde
// I don't know how exactly right now just having it here instead
let entries = [
Entry {
name: "typeshed/LICENSE".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{f016}',
color: "#7e8e91",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/README.md".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{f48a}',
color: "#dddddd",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/re.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/io.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/gc.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/uu.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/nt.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/dis.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/imp.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/bdb.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/abc.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/cgi.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/bz2.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/grp.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/ast.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/csv.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/pdb.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/pwd.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/ssl.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/tty.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/nis.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/pty.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/cmd.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/tests/utils.py".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/pyproject.toml".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e6b2}',
color: "#9c4221",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/MAINTAINERS.md".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{f48a}',
color: "#dddddd",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/enum.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/hmac.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/uuid.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/glob.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/_ast.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/_csv.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/code.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/spwd.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/_msi.pyi".to_string(),
value: None,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
},
Entry {
name: "typeshed/stdlib/time.pyi".to_string(),
value: None,
icon: Some(FileIcon {
icon: '\u{e606}',
color: "#ffbc03",
}),
line_number: None,
preview_type: PreviewType::Files,
name_match_ranges: Some(into_ranges(&[0, 1, 2, 3])),
value_match_ranges: None,
},
];
let colorscheme = ResultsColorscheme {
result_name_fg: Color::Indexed(222),
result_preview_fg: Color::Indexed(222),
result_line_number_fg: Color::Indexed(222),
result_selected_fg: Color::Indexed(222),
result_selected_bg: Color::Indexed(222),
match_foreground_color: Color::Indexed(222),
};
c.bench_function("results_list", |b| {
b.iter(|| {
build_results_list(
Block::default()
.title_top(
Line::from(" Results ").alignment(Alignment::Center),
)
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Blue))
.style(Style::default())
.padding(Padding::right(1)),
&entries,
None,
ListDirection::BottomToTop,
false,
&colorscheme,
100,
);
});
});
}
pub fn draw(c: &mut Criterion) {
let width = 250;
let height = 80;
let rt = Runtime::new().unwrap();
c.bench_function("draw", |b| {
b.to_async(&rt).iter_batched(
// FIXME: this is kind of hacky
|| {
let config = Config::new(&ConfigEnv::init().unwrap()).unwrap();
let backend = TestBackend::new(width, height);
let terminal = Terminal::new(backend).unwrap();
let (tx, _) = tokio::sync::mpsc::unbounded_channel();
let mut channel =
TelevisionChannel::Files(Channel::new(vec![
PathBuf::from("."),
]));
channel.find("television");
// Wait for the channel to finish loading
let mut tv = Television::new(
tx, channel, config, None, false, false, false,
);
for _ in 0..5 {
// tick the matcher
let _ = tv.channel.results(10, 0);
std::thread::sleep(std::time::Duration::from_millis(10));
}
tv.select_next_entry(10);
let _ = tv.update_preview_state(
&tv.get_selected_entry(None).unwrap(),
);
let _ = tv.update(&Action::Tick);
(tv, terminal)
},
// Measurement
|(tv, mut terminal)| async move {
television::draw::draw(
black_box(&tv.dump_context()),
black_box(&mut terminal.get_frame()),
black_box(Rect::new(0, 0, width, height)),
)
.unwrap();
},
criterion::BatchSize::SmallInput,
);
});
}
criterion_group!(benches, draw_results_list, draw);