Skip to content

Commit

Permalink
feat: readd index tiebreak (#609)
Browse files Browse the repository at this point in the history
* readd index tiebreak

* clippy & fmt

* doc

* use index tiebreak in shell scripts

* revert man & completions for merge

* compgen & mangen

---------

Co-authored-by: LoricAndre <loric.andre@pm.me>
  • Loading branch information
LoricAndre and LoricAndre authored Nov 26, 2024
1 parent ad909c3 commit 0befe8d
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 39 deletions.
6 changes: 3 additions & 3 deletions man/man1/sk.1
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Comma\-separated list of sort criteria to apply when the scores are tied.
.br

.br
[\fIpossible values: \fRscore, \-score, begin, \-begin, end, \-end, length, \-length]
[\fIpossible values: \fRscore, \-score, begin, \-begin, end, \-end, length, \-length, index, \-index]
.TP
\fB\-n\fR, \fB\-\-nth\fR=\fINTH\fR [default: ]
Fields to be matched
Expand Down Expand Up @@ -408,15 +408,15 @@ Number of lines of the input treated as header

The first N lines of the input are treated as the sticky header. When \-\-with\-nth is set, the lines are transformed just like the other lines that follow.
.TP
\fB\-\-history\fR=\fIHISTORY\fR
\fB\-\-history\fR=\fIHISTORY_FILE\fR
History file

Load search history from the specified file and update the file on completion. When enabled, CTRL\-N and CTRL\-P are automatically remapped to next\-history and previous\-history.
.TP
\fB\-\-history\-size\fR=\fIHISTORY_SIZE\fR [default: 1000]
Maximum number of query history entries to keep
.TP
\fB\-\-cmd\-history\fR=\fICMD_HISTORY\fR
\fB\-\-cmd\-history\fR=\fICMD_HISTORY_FILE\fR
Command history file

Load command query history from the specified file and update the file on completion. When enabled, CTRL\-N and CTRL\-P are automatically remapped to next\-history and previous\-history.
Expand Down
4 changes: 2 additions & 2 deletions shell/completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ _sk() {
fi
case "${prev}" in
--tiebreak)
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length" -- "${cur}"))
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index" -- "${cur}"))
return 0
;;
-t)
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length" -- "${cur}"))
COMPREPLY=($(compgen -W "score -score begin -begin end -end length -length index -index" -- "${cur}"))
return 0
;;
--nth)
Expand Down
8 changes: 4 additions & 4 deletions shell/completion.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ _sk() {

local context curcontext="$curcontext" state line
_arguments "${_arguments_options[@]}" : \
'*-t+[Comma-separated list of sort criteria to apply when the scores are tied.]:TIEBREAK:(score -score begin -begin end -end length -length)' \
'*--tiebreak=[Comma-separated list of sort criteria to apply when the scores are tied.]:TIEBREAK:(score -score begin -begin end -end length -length)' \
'*-t+[Comma-separated list of sort criteria to apply when the scores are tied.]:TIEBREAK:(score -score begin -begin end -end length -length index -index)' \
'*--tiebreak=[Comma-separated list of sort criteria to apply when the scores are tied.]:TIEBREAK:(score -score begin -begin end -end length -length index -index)' \
'*-n+[Fields to be matched]:NTH:_default' \
'*--nth=[Fields to be matched]:NTH:_default' \
'*--with-nth=[Fields to be transformed]:WITH_NTH:_default' \
Expand All @@ -41,9 +41,9 @@ _sk() {
'--tabstop=[Number of spaces that make up a tab]:TABSTOP:_default' \
'--header=[Set header, displayed next to the info]:HEADER:_default' \
'--header-lines=[Number of lines of the input treated as header]:HEADER_LINES:_default' \
'--history=[History file]:HISTORY:_default' \
'--history=[History file]:HISTORY_FILE:_default' \
'--history-size=[Maximum number of query history entries to keep]:HISTORY_SIZE:_default' \
'--cmd-history=[Command history file]:CMD_HISTORY:_default' \
'--cmd-history=[Command history file]:CMD_HISTORY_FILE:_default' \
'--cmd-history-size=[Maximum number of query history entries to keep]:CMD_HISTORY_SIZE:_default' \
'--preview=[Preview command]:PREVIEW:_default' \
'--preview-window=[Preview window layout]:PREVIEW_WINDOW:_default' \
Expand Down
27 changes: 24 additions & 3 deletions skim/examples/downcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use skim::prelude::*;
#[derive(Debug, Clone)]
struct Item {
text: String,
index: usize,
}

impl SkimItem for Item {
Expand All @@ -17,6 +18,14 @@ impl SkimItem for Item {
fn preview(&self, _context: PreviewContext) -> ItemPreview {
ItemPreview::Text(self.text.to_owned())
}

fn get_index(&self) -> usize {
self.index
}

fn set_index(&mut self, index: usize) {
self.index = index
}
}

pub fn main() {
Expand All @@ -29,9 +38,21 @@ pub fn main() {

let (tx, rx): (SkimItemSender, SkimItemReceiver) = unbounded();

tx.send(Arc::new(Item { text: "a".to_string() })).unwrap();
tx.send(Arc::new(Item { text: "b".to_string() })).unwrap();
tx.send(Arc::new(Item { text: "c".to_string() })).unwrap();
tx.send(Arc::new(Item {
text: "a".to_string(),
index: 0,
}))
.unwrap();
tx.send(Arc::new(Item {
text: "b".to_string(),
index: 1,
}))
.unwrap();
tx.send(Arc::new(Item {
text: "c".to_string(),
index: 2,
}))
.unwrap();

drop(tx);

Expand Down
2 changes: 1 addition & 1 deletion skim/src/engine/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl MatchEngine for MatchAllEngine {
fn match_item(&self, item: Arc<dyn SkimItem>) -> Option<MatchResult> {
let item_len = item.text().len();
Some(MatchResult {
rank: self.rank_builder.build_rank(0, 0, 0, item_len),
rank: self.rank_builder.build_rank(0, 0, 0, item_len, item.get_index()),
matched_range: MatchRange::ByteRange(0, 0),
})
}
Expand Down
4 changes: 3 additions & 1 deletion skim/src/engine/exact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ impl MatchEngine for ExactEngine {
let score = (end - begin) as i32;
let item_len = item_text.len();
Some(MatchResult {
rank: self.rank_builder.build_rank(score, begin, end, item_len),
rank: self
.rank_builder
.build_rank(score, begin, end, item_len, item.get_index()),
matched_range: MatchRange::ByteRange(begin, end),
})
}
Expand Down
5 changes: 4 additions & 1 deletion skim/src/engine/fuzzy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,15 @@ impl MatchEngine for FuzzyEngine {

let (score, matched_range) = matched_result.unwrap();

trace!("matched range {:?}", matched_range);
let begin = *matched_range.first().unwrap_or(&0);
let end = *matched_range.last().unwrap_or(&0);

let item_len = item_text.len();
Some(MatchResult {
rank: self.rank_builder.build_rank(score as i32, begin, end, item_len),
rank: self
.rank_builder
.build_rank(score as i32, begin, end, item_len, item.get_index()),
matched_range: MatchRange::Chars(matched_range),
})
}
Expand Down
4 changes: 3 additions & 1 deletion skim/src/engine/regexp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ impl MatchEngine for RegexEngine {
let item_len = item_text.len();

Some(MatchResult {
rank: self.rank_builder.build_rank(score, begin, end, item_len),
rank: self
.rank_builder
.build_rank(score, begin, end, item_len, item.get_index()),
matched_range: MatchRange::ByteRange(begin, end),
})
}
Expand Down
12 changes: 12 additions & 0 deletions skim/src/helper/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub struct DefaultSkimItem {
// Option<Box<_>> to reduce memory use in normal cases where no matching ranges are specified.
#[allow(clippy::box_collection)]
matching_ranges: Option<Box<Vec<(usize, usize)>>>,
/// The index, for use in matching
index: usize,
}

impl DefaultSkimItem {
Expand All @@ -38,6 +40,7 @@ impl DefaultSkimItem {
trans_fields: &[FieldRange],
matching_fields: &[FieldRange],
delimiter: &Regex,
index: usize,
) -> Self {
let using_transform_fields = !trans_fields.is_empty();

Expand Down Expand Up @@ -83,6 +86,7 @@ impl DefaultSkimItem {
orig_text,
text,
matching_ranges,
index,
}
}
}
Expand Down Expand Up @@ -129,4 +133,12 @@ impl SkimItem for DefaultSkimItem {
ret.override_attrs(new_fragments);
ret
}

fn get_index(&self) -> usize {
self.index
}

fn set_index(&mut self, index: usize) {
self.index = index;
}
}
12 changes: 7 additions & 5 deletions skim/src/helper/item_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,16 +256,14 @@ impl SkimItemReader {
started_clone.store(true, Ordering::SeqCst); // notify parent that it is started

let mut buffer = Vec::with_capacity(option.buf_size);
let mut line_idx = 0;
loop {
buffer.clear();

// start reading
match source.read_until(option.line_ending, &mut buffer) {
Ok(n) => {
if n == 0 {
break;
}

Ok(0) => break,
Ok(_) => {
if buffer.ends_with(b"\r\n") {
buffer.pop();
buffer.pop();
Expand All @@ -275,12 +273,15 @@ impl SkimItemReader {

let line = String::from_utf8_lossy(&buffer).to_string();

trace!("got item {} with index {} from command", line.clone(), line_idx);

let raw_item = DefaultSkimItem::new(
line,
option.use_ansi_color,
&option.transform_fields,
&option.matching_fields,
&option.delimiter,
line_idx,
);

match tx_item.send(Arc::new(raw_item)) {
Expand All @@ -290,6 +291,7 @@ impl SkimItemReader {
break;
}
}
line_idx += 1;
}
Err(_err) => {} // String not UTF8 or other error, skip.
}
Expand Down
26 changes: 18 additions & 8 deletions skim/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,31 @@ impl RankBuilder {
}

/// score: the greater the better
pub fn build_rank(&self, score: i32, begin: usize, end: usize, length: usize) -> Rank {
pub fn build_rank(&self, score: i32, begin: usize, end: usize, length: usize, index: usize) -> Rank {
let mut rank = [0; 4];
let begin = begin as i32;
let end = end as i32;
let length = length as i32;
let index = index as i32;

for (index, criteria) in self.criterion.iter().take(4).enumerate() {
for (priority, criteria) in self.criterion.iter().take(5).enumerate() {
let value = match criteria {
RankCriteria::Score => -score,
RankCriteria::Begin => begin,
RankCriteria::End => end,
RankCriteria::NegScore => score,
RankCriteria::Begin => begin,
RankCriteria::NegBegin => -begin,
RankCriteria::End => end,
RankCriteria::NegEnd => -end,
RankCriteria::Length => length,
RankCriteria::NegLength => -length,
RankCriteria::Index => index,
RankCriteria::NegIndex => -index,
};

rank[index] = value;
rank[priority] = value;
}

trace!("ranks: {:?}", rank);
rank
}
}
Expand Down Expand Up @@ -202,19 +206,23 @@ impl<'mutex, T: Sized> Deref for ItemPoolGuard<'mutex, T> {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum RankCriteria {
Score,
Begin,
End,
NegScore,
Begin,
NegBegin,
End,
NegEnd,
Length,
NegLength,
Index,
NegIndex,
}

impl ValueEnum for RankCriteria {
fn value_variants<'a>() -> &'a [Self] {
use RankCriteria::*;
&[Score, NegScore, Begin, NegBegin, End, NegEnd, Length, NegLength]
&[
Score, NegScore, Begin, NegBegin, End, NegEnd, Length, NegLength, Index, NegIndex,
]
}

fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
Expand All @@ -228,6 +236,8 @@ impl ValueEnum for RankCriteria {
NegEnd => PossibleValue::new("-end"),
Length => PossibleValue::new("length"),
NegLength => PossibleValue::new("-length"),
Index => PossibleValue::new("index"),
NegIndex => PossibleValue::new("-index"),
})
}
}
11 changes: 11 additions & 0 deletions skim/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ pub trait SkimItem: AsAny + Send + Sync + 'static {
fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> {
None
}

/// Get index, for matching purposes
///
/// Implemented as no-op for retro-compatibility purposes
fn get_index(&self) -> usize {
0
}
/// Set index, for matching purposes
///
/// Implemented as no-op for retro-compatibility purposes
fn set_index(&mut self, _index: usize) {}
}

//------------------------------------------------------------------------------
Expand Down
7 changes: 4 additions & 3 deletions skim/src/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Matcher {
let matched_items_clone = matched_items.clone();

let thread_matcher = thread::spawn(move || {
let num_taken = item_pool.num_taken();
let _num_taken = item_pool.num_taken();
let items = item_pool.take();

// 1. use rayon for parallel
Expand All @@ -94,7 +94,8 @@ impl Matcher {
let result: Result<Vec<_>, _> = items
.into_par_iter()
.enumerate()
.filter_map(|(index, item)| {
.filter_map(|(_, item)| {
let item_idx = item.get_index();
processed.fetch_add(1, Ordering::Relaxed);
if stopped.load(Ordering::Relaxed) {
Some(Err("matcher killed"))
Expand All @@ -104,7 +105,7 @@ impl Matcher {
item: item.clone(),
rank: match_result.rank,
matched_range: Some(match_result.matched_range),
item_idx: (num_taken + index) as u32,
item_idx: item_idx as u32,
}))
} else {
None
Expand Down
Loading

0 comments on commit 0befe8d

Please sign in to comment.