Skip to content

Commit a1f420a

Browse files
committed
chore: clippy pedantic
1 parent 85c6964 commit a1f420a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1013
-687
lines changed

bench.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
This measures how fast skim can ingest items and display matched results.
55
66
Usage: bench.py [BINARY_PATH ...] [-n|--num-items NUM] [-q|--query QUERY]
7-
[-r|--runs RUNS] [-f|--file FILE] [-g|--generate-file FILE]
8-
[-j|--json] [-- EXTRA_ARGS...]
7+
[-r|--runs RUNS] [-w|--warmup N] [-f|--file FILE]
8+
[-g|--generate-file FILE] [-j|--json] [-- EXTRA_ARGS...]
99
1010
Arguments:
1111
BINARY_PATH ... One or more paths to binaries (default: ./target/release/sk)
@@ -14,6 +14,7 @@
1414
-n, --num-items NUM Number of items to generate (default: 1000000)
1515
-q, --query QUERY Query string to search (default: "test")
1616
-r, --runs RUNS Number of benchmark runs per binary (default: 1)
17+
-w, --warmup N Number of warmup runs per binary (default: 1)
1718
-f, --file FILE Use existing file as input instead of generating
1819
-g, --generate-file FILE Generate test data to file and exit
1920
-j, --json Output results as JSON
@@ -44,6 +45,7 @@
4445
DEFAULT_NUM_ITEMS = 1_000_000
4546
DEFAULT_QUERY = "test"
4647
DEFAULT_RUNS = 1
48+
DEFAULT_WARMUP = 1
4749

4850
# Stability / timeout tuning (mirrors bench.sh values)
4951
REQUIRED_STABLE_S = 5.0 # seconds the matched count must be unchanged
@@ -129,6 +131,7 @@ def parse_args(argv):
129131
parser.add_argument("-n", "--num-items", type=int, default=DEFAULT_NUM_ITEMS)
130132
parser.add_argument("-q", "--query", default=DEFAULT_QUERY)
131133
parser.add_argument("-r", "--runs", type=int, default=DEFAULT_RUNS)
134+
parser.add_argument("-w", "--warmup", type=int, default=DEFAULT_WARMUP)
132135
parser.add_argument("-f", "--file", default="")
133136
parser.add_argument("-g", "--generate-file", default="")
134137
parser.add_argument("-j", "--json", action="store_true")
@@ -423,12 +426,13 @@ def _max(values):
423426

424427

425428
def aggregate(results: list) -> dict:
426-
times = [r["elapsed_s"] for r in results]
427-
rates = [r["rate"] for r in results]
428-
matched = [r["matched"] for r in results]
429-
mems = [r["peak_mem_kb"] for r in results]
430-
cpus = [r["peak_cpu"] for r in results]
431-
completed = sum(1 for r in results if r["completed"])
429+
completed_results = [r for r in results if r["completed"]]
430+
times = [r["elapsed_s"] for r in completed_results]
431+
rates = [r["rate"] for r in completed_results]
432+
matched = [r["matched"] for r in completed_results]
433+
mems = [r["peak_mem_kb"] for r in completed_results]
434+
cpus = [r["peak_cpu"] for r in completed_results]
435+
completed = len(completed_results)
432436

433437
return {
434438
"completed": completed,
@@ -611,6 +615,7 @@ def main():
611615
num_items = opts.num_items
612616
query = opts.query
613617
runs = opts.runs
618+
warmup = opts.warmup
614619
input_file = opts.file
615620
generate_file = opts.generate_file
616621
as_json = opts.json
@@ -645,14 +650,33 @@ def main():
645650
print(f"=== Skim Ingestion + Matching Benchmark ===", file=sys.stderr)
646651
print(
647652
f"Binaries: {binary_list} | Items: {num_items} | "
648-
f"Query: '{query}' | Runs: {runs} (per binary)",
653+
f"Query: '{query}' | Warmup: {warmup} | Runs: {runs} (per binary)",
649654
file=sys.stderr,
650655
)
651656
if input_file:
652657
print(f"Input file: {input_file}", file=sys.stderr)
653658
if extra_args:
654659
print(f"Extra args: {' '.join(extra_args)}", file=sys.stderr)
655660

661+
# ---- warmup (results discarded) -------------------------------------
662+
if warmup > 0:
663+
print(f"\n=== Warmup ({warmup} run(s) per binary) ===", file=sys.stderr)
664+
for bi, binary in enumerate(binaries):
665+
for wu in range(1, warmup + 1):
666+
print(
667+
f" Warmup {wu}/{warmup}{binary} ...",
668+
file=sys.stderr,
669+
)
670+
run_once(
671+
binary_path=binary,
672+
query=query,
673+
tmp_file=tmp_file,
674+
num_items=num_items,
675+
extra_args=extra_args,
676+
run_index=wu,
677+
session_suffix=f"warmup_b{bi}",
678+
)
679+
656680
# ---- run benchmark in round-robin -----------------------------------
657681
# all_results[i] = list of per-run dicts for binaries[i]
658682
all_results = [[] for _ in binaries]

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
cargo-insta
1717
cargo-llvm-cov
1818
cargo-edit
19+
cargo-public-api
1920
git-cliff
2021
libclang
2122
binutils

src/bin/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ fn sk_main(mut opts: SkimOptions) -> Result<i32> {
182182
output_format,
183183
&bin_options.delimiter,
184184
&bin_options.replstr,
185-
result.selected_items.iter(),
186-
result.current,
185+
&result.selected_items.iter(),
186+
&result.current,
187187
&result.query,
188188
&result.cmd,
189189
true

src/binds.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl Default for KeyMap {
4444
}
4545

4646
impl KeyMap {
47-
/// Adds keymaps from the source, parsing them using parse_keymap
47+
/// Adds keymaps from the source, parsing them using `parse_keymap`
4848
pub fn add_keymaps<'a, T>(&mut self, source: T)
4949
where
5050
T: Iterator<Item = &'a str>,
@@ -70,6 +70,7 @@ impl KeyMap {
7070

7171
/// Returns the default key bindings for skim
7272
#[rustfmt::skip]
73+
#[must_use]
7374
pub fn get_default_key_map() -> KeyMap {
7475
let mut ret = HashMap::new();
7576

@@ -132,7 +133,11 @@ pub fn get_default_key_map() -> KeyMap {
132133
KeyMap(ret)
133134
}
134135

135-
/// Parses a key str into a crossterm KeyEvent
136+
/// Parses a key str into a crossterm `KeyEvent`
137+
///
138+
/// # Errors
139+
/// Returns an error if the key string is empty, contains an unknown modifier,
140+
/// or does not correspond to a recognised key name.
136141
pub fn parse_key(key: &str) -> Result<KeyEvent> {
137142
if key.is_empty() {
138143
return Err(eyre!("Cannot parse empty key"));
@@ -155,15 +160,15 @@ pub fn parse_key(key: &str) -> Result<KeyEvent> {
155160

156161
let keycode: KeyCode;
157162
if key.len() == 1 {
158-
let char = key.chars().next().unwrap();
163+
let char = key.chars().next().unwrap_or_default();
159164
if char.is_uppercase() {
160165
mods |= KeyModifiers::SHIFT;
161-
keycode = KeyCode::Char(char.to_lowercase().next().unwrap());
166+
keycode = KeyCode::Char(char.to_ascii_lowercase());
162167
} else {
163168
keycode = KeyCode::Char(char);
164169
}
165-
} else if key.starts_with("f") {
166-
let f_index = key.strip_prefix("f").unwrap().parse::<u8>()?;
170+
} else if let Some(f) = key.strip_prefix('f') {
171+
let f_index = f.parse::<u8>()?;
167172
keycode = KeyCode::F(f_index);
168173
} else {
169174
keycode = match key.as_str() {
@@ -191,7 +196,7 @@ pub fn parse_key(key: &str) -> Result<KeyEvent> {
191196
Ok(KeyEvent::new(keycode, mods))
192197
}
193198

194-
/// Parse an iterator of keymaps into a KeyMap
199+
/// Parse an iterator of keymaps into a `KeyMap`
195200
pub fn parse_keymaps<'a, T>(maps: T) -> KeyMap
196201
where
197202
T: Iterator<Item = &'a str>,
@@ -202,12 +207,15 @@ where
202207
}
203208

204209
/// Parses an action chain, separated by '+'s into the corresponding actions
210+
///
211+
/// # Errors
212+
/// Returns an error if the action chain is empty or contains only unknown actions.
205213
pub fn parse_action_chain(action_chain: &str) -> Result<Vec<Action>> {
206214
let mut actions: Vec<Action> = vec![];
207-
let mut split = action_chain.split("+");
215+
let mut split = action_chain.split('+');
208216

209217
while let Some(mut s) = split.next().map(String::from) {
210-
if (s.starts_with("if-") || s.ends_with("{"))
218+
if (s.starts_with("if-") || s.ends_with('{'))
211219
&& let Some(otherwise) = split.next()
212220
{
213221
s += &(String::from("+") + otherwise);
@@ -224,15 +232,19 @@ pub fn parse_action_chain(action_chain: &str) -> Result<Vec<Action>> {
224232
}
225233

226234
/// Parse a single keymap and return the key and action(s)
235+
///
236+
/// # Errors
237+
/// Returns an error if the string is empty, missing a colon separator, or the
238+
/// action chain cannot be parsed.
227239
pub fn parse_keymap(key_action: &str) -> Result<(&str, Vec<Action>)> {
228240
if key_action.is_empty() {
229241
return Err(eyre!("Got an empty keybind, skipping"));
230242
}
231-
debug!("got key_action: {:?}", key_action);
243+
debug!("got key_action: {key_action:?}");
232244
let (key, action_chain) = key_action
233245
.split_once(':')
234246
.ok_or(eyre!("Failed to parse {} as key and action", key_action))?;
235-
debug!("parsed key_action: {:?}: {:?}", key, action_chain);
247+
debug!("parsed key_action: {key:?}: {action_chain:?}");
236248
Ok((key, parse_action_chain(action_chain)?))
237249
}
238250

src/engine/andor.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl AndEngine {
7070
self
7171
}
7272

73-
fn merge_matched_items(&self, items: Vec<MatchResult>, text: &str) -> MatchResult {
73+
fn merge_matched_items(items: Vec<MatchResult>, text: &str) -> MatchResult {
7474
let mut ranges = MatchIndices::new();
7575
let mut rank = crate::Rank {
7676
score: 0,
@@ -92,7 +92,7 @@ impl AndEngine {
9292
rank.end = rank.end.max(item.rank.end);
9393
}
9494

95-
ranges.sort();
95+
ranges.sort_unstable();
9696
ranges.dedup();
9797
MatchResult {
9898
rank,
@@ -113,7 +113,7 @@ impl MatchEngine for AndEngine {
113113
if results.is_empty() {
114114
None
115115
} else {
116-
Some(self.merge_matched_items(results, &item.text()))
116+
Some(Self::merge_matched_items(results, &item.text()))
117117
}
118118
}
119119
}

src/engine/exact.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ impl MatchEngine for ExactEngine {
8787
}
8888

8989
matched_result =
90-
regex_match(&item_text[start..end], &self.query_regex).map(|(s, e)| (s + start, e + start));
90+
regex_match(&item_text[start..end], self.query_regex.as_ref()).map(|(s, e)| (s + start, e + start));
9191

9292
if self.inverse {
93-
matched_result = matched_result.xor(Some((0, 0)))
93+
matched_result = matched_result.xor(Some((0, 0)));
9494
}
9595

9696
if matched_result.is_some() {
@@ -99,7 +99,7 @@ impl MatchEngine for ExactEngine {
9999
}
100100

101101
let (begin, end) = matched_result?;
102-
let score = (end - begin) as i32;
102+
let score = i32::try_from(end - begin).unwrap_or(i32::MAX);
103103
Some(MatchResult {
104104
rank: self.rank_builder.build_rank(score, begin, end, &item_text),
105105
matched_range: MatchRange::ByteRange(begin, end),
@@ -113,7 +113,7 @@ impl Display for ExactEngine {
113113
f,
114114
"(Exact|{}{})",
115115
if self.inverse { "!" } else { "" },
116-
self.query_regex.as_ref().map(|x| x.as_str()).unwrap_or("")
116+
self.query_regex.as_ref().map_or("", regex::Regex::as_str)
117117
)
118118
}
119119
}

src/engine/factory.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct ExactOrFuzzyEngineFactory {
2525

2626
impl ExactOrFuzzyEngineFactory {
2727
/// Creates a new builder with default settings
28+
#[must_use]
2829
pub fn builder() -> Self {
2930
Self {
3031
exact_mode: false,
@@ -37,18 +38,21 @@ impl ExactOrFuzzyEngineFactory {
3738
}
3839

3940
/// Sets whether to use exact matching mode
41+
#[must_use]
4042
pub fn exact_mode(mut self, exact_mode: bool) -> Self {
4143
self.exact_mode = exact_mode;
4244
self
4345
}
4446

4547
/// Sets the fuzzy matching algorithm to use
48+
#[must_use]
4649
pub fn fuzzy_algorithm(mut self, fuzzy_algorithm: FuzzyAlgorithm) -> Self {
4750
self.fuzzy_algorithm = fuzzy_algorithm;
4851
self
4952
}
5053

5154
/// Sets the rank builder for scoring matches
55+
#[must_use]
5256
pub fn rank_builder(mut self, rank_builder: Arc<RankBuilder>) -> Self {
5357
self.rank_builder = rank_builder;
5458
self
@@ -57,26 +61,30 @@ impl ExactOrFuzzyEngineFactory {
5761
/// Sets the typo tolerance configuration
5862
///
5963
/// - `Typos::Disabled`: no typo tolerance
60-
/// - `Typos::Smart`: adaptive typo tolerance (pattern_length / 4)
64+
/// - `Typos::Smart`: adaptive typo tolerance (`pattern_length` / 4)
6165
/// - `Typos::Fixed(n)`: exactly n typos allowed
66+
#[must_use]
6267
pub fn typos(mut self, typos: Typos) -> Self {
6368
self.typos = typos;
6469
self
6570
}
6671

6772
/// Sets filter mode (skips per-character match indices for faster matching)
73+
#[must_use]
6874
pub fn filter_mode(mut self, filter_mode: bool) -> Self {
6975
self.filter_mode = filter_mode;
7076
self
7177
}
7278

7379
/// When true, prefer the last (rightmost) occurrence on tied scores
80+
#[must_use]
7481
pub fn last_match(mut self, last_match: bool) -> Self {
7582
self.last_match = last_match;
7683
self
7784
}
7885

7986
/// Builds the factory (currently a no-op, returns self)
87+
#[must_use]
8088
pub fn build(self) -> Self {
8189
self
8290
}
@@ -170,7 +178,7 @@ impl AndOrEngineFactory {
170178
return self.inner.create_engine_with_case(query, case);
171179
}
172180
let and_engines = RE_OR_WITH_SPACES
173-
.replace_all(&self.mask_escape_space(query), "|")
181+
.replace_all(&Self::mask_escape_space(query), "|")
174182
.split(' ')
175183
.filter_map(|and_term| {
176184
if and_term.is_empty() {
@@ -185,7 +193,7 @@ impl AndOrEngineFactory {
185193
debug!("Creating Or engine for {term}");
186194
Some(
187195
self.inner
188-
.create_engine_with_case(&self.unmask_escape_space(term), case),
196+
.create_engine_with_case(&Self::unmask_escape_space(term), case),
189197
)
190198
})
191199
.collect::<Vec<_>>();
@@ -200,11 +208,11 @@ impl AndOrEngineFactory {
200208
Box::new(AndEngine::builder().engines(and_engines).build())
201209
}
202210

203-
fn mask_escape_space(&self, string: &str) -> String {
211+
fn mask_escape_space(string: &str) -> String {
204212
string.replace("\\ ", "\0")
205213
}
206214

207-
fn unmask_escape_space(&self, string: &str) -> String {
215+
fn unmask_escape_space(string: &str) -> String {
208216
string.replace('\0', " ")
209217
}
210218
}
@@ -223,19 +231,22 @@ pub struct RegexEngineFactory {
223231

224232
impl RegexEngineFactory {
225233
/// Creates a new builder with default settings
234+
#[must_use]
226235
pub fn builder() -> Self {
227236
Self {
228237
rank_builder: Default::default(),
229238
}
230239
}
231240

232241
/// Sets the rank builder for scoring matches
242+
#[must_use]
233243
pub fn rank_builder(mut self, rank_builder: Arc<RankBuilder>) -> Self {
234244
self.rank_builder = rank_builder;
235245
self
236246
}
237247

238248
/// Builds the factory (currently a no-op, returns self)
249+
#[must_use]
239250
pub fn build(self) -> Self {
240251
self
241252
}

0 commit comments

Comments
 (0)