diff --git a/Cargo.lock b/Cargo.lock index be813b15..22523893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,9 +124,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" -version = "1.1.36" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "shlex", ] @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -163,9 +163,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -175,9 +175,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -216,9 +216,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clap_mangen" @@ -522,9 +522,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.162" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libredox" @@ -678,9 +678,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -707,18 +707,18 @@ checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -797,18 +797,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", diff --git a/README.md b/README.md index 5497d1a0..aabf2033 100644 --- a/README.md +++ b/README.md @@ -59,14 +59,16 @@ The skim project contains several components: ## Package Managers -| Distribution | Package Manager | Command | -| -------------- | ----------------- | ---------------------------- | -| macOS | Homebrew | `brew install sk` | -| macOS | MacPorts | `sudo port install skim` | -| Fedora | dnf | `dnf install skim` | -| Alpine | apk | `apk add skim` | -| Arch | pacman | `pacman -S skim` | +| Distribution | Package Manager | Command | +| -------------- | ----------------- | ------------------------- | +| macOS | Homebrew | `brew install sk` | +| macOS | MacPorts | `sudo port install skim` | +| Fedora | dnf | `dnf install skim` | +| Alpine | apk | `apk add skim` | +| Arch | pacman | `pacman -S skim` | | Gentoo | Portage | `emerge --ask app-misc/skim` | +| Guix | guix | `guix install skim` | +| Void | XBPS | `xbps-install -S skim` | See [repology](https://repology.org/project/skim/versions) for a comprehensive overview of package availability. diff --git a/plugin/skim.vim b/plugin/skim.vim index f633e2b2..f91d4dc9 100644 --- a/plugin/skim.vim +++ b/plugin/skim.vim @@ -342,6 +342,12 @@ function! skim#wrap(...) endif endif + " Interactive commands should use --cmd-history for query history + let history_option = '--history' + if index(opts['options'], '-i') != -1 + let history_option = '--cmd-history' + endif + " Colors: g:skim_colors let opts.options = s:defaults() .' '. s:evaluate_opts(get(opts, 'options', '')) @@ -352,7 +358,7 @@ function! skim#wrap(...) call mkdir(dir, 'p') endif let history = skim#shellescape(dir.'/'.name) - let opts.options = join(['--history', history, opts.options]) + let opts.options = join([history_option, history, opts.options]) endif " Action: g:skim_action diff --git a/shell/key-bindings.zsh b/shell/key-bindings.zsh index ac99db2a..0d695e24 100644 --- a/shell/key-bindings.zsh +++ b/shell/key-bindings.zsh @@ -118,8 +118,23 @@ bindkey '\ec' skim-cd-widget skim-history-widget() { local selected num setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null - selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\**\s+(.*)/, $1)}++' | - SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --query=${(qqq)LBUFFER} --no-multi" $(__skimcmd)) ) + local awk_filter='{ cmd=$0; sub(/^\s*[0-9]+\**\s+/, "", cmd); if (!seen[cmd]++) print $0 }' # filter out duplicates + local n=2 fc_opts='' + if [[ -o extended_history ]]; then + local today=$(date +%Y-%m-%d) + # For today's commands, replace date ($2) with "today", otherwise remove time ($3). + # And filter out duplicates. + awk_filter='{ + if ($2 == "'$today'") sub($2 " ", "today'\''") + else sub($3, "") + line=$0; $1=""; $2=""; $3="" + if (!seen[$0]++) print line + }' + fc_opts='-i' + n=3 + fi + selected=( $(fc -rl $fc_opts 1 | awk "$awk_filter" | + SKIM_DEFAULT_OPTIONS="--height ${SKIM_TMUX_HEIGHT:-40%} $SKIM_DEFAULT_OPTIONS -n$n..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $SKIM_CTRL_R_OPTS --query=${(qqq)LBUFFER} --no-multi" $(__skimcmd)) ) local ret=$? if [ -n "$selected" ]; then num=$selected[1] diff --git a/skim/src/ansi.rs b/skim/src/ansi.rs index 61d29328..832d4b01 100644 --- a/skim/src/ansi.rs +++ b/skim/src/ansi.rs @@ -75,7 +75,7 @@ impl Perform for ANSIParser { match code[0] { 0 => attr = Attr::default(), 1 => attr.effect |= Effect::BOLD, - 2 => attr.effect |= !Effect::BOLD, + 2 => attr.effect |= Effect::DIM, 4 => attr.effect |= Effect::UNDERLINE, 5 => attr.effect |= Effect::BLINK, 7 => attr.effect |= Effect::REVERSE, @@ -324,6 +324,24 @@ impl<'a> From<(&'a str, &'a [usize], Attr)> for AnsiString<'a> { } } +impl<'a> std::ops::Add for AnsiString<'a> { + type Output = AnsiString<'a>; + + fn add(mut self, rhs: Self) -> Self::Output { + let len = self.stripped.as_ref().len() as u32; + if let Some(fragments) = rhs.fragments { + if self.fragments.is_none() { + self.fragments = Some(vec![]); + } + for (attr, (start, end)) in fragments.iter() { + self.fragments.as_mut().unwrap().push((*attr, (start + len, end + len))); + } + } + self.stripped = Cow::owned(self.stripped.into_owned() + rhs.stripped.as_ref()); + self + } +} + /// An iterator over all the (char, attr) characters. pub struct AnsiStringIterator<'a> { fragments: &'a [(Attr, (u32, u32))], @@ -595,6 +613,26 @@ mod tests { ); } + #[test] + fn test_ansi_string_add() { + let default_attr = Attr::default(); + let ar = Attr::default().bg(Color::RED); + let ab = Attr::default().bg(Color::BLUE); + + let string_a = AnsiString::new_str("foo", vec![(ar, (1, 3))]); + let string_b = AnsiString::new_str("bar", vec![(ab, (0, 2))]); + let string_c = string_a + string_b; + + let mut it = string_c.iter(); + assert_eq!(Some(('f', default_attr)), it.next()); + assert_eq!(Some(('o', ar)), it.next()); + assert_eq!(Some(('o', ar)), it.next()); + assert_eq!(Some(('b', ab)), it.next()); + assert_eq!(Some(('a', ab)), it.next()); + assert_eq!(Some(('r', default_attr)), it.next()); + assert_eq!(None, it.next()); + } + #[test] fn test_multi_byte_359() { // https://github.com/lotabout/skim/issues/359 @@ -606,4 +644,21 @@ mod tests { assert_eq!(Some(('a', highlight)), it.next()); assert_eq!(None, it.next()); } + + #[test] + fn test_ansi_dim() { + // https://github.com/lotabout/skim/issues/495 + let input = "\x1B[2mhi\x1b[0m"; + let ansistring = ANSIParser::default().parse_ansi(input); + let mut it = ansistring.iter(); + let attr = Attr { + effect: Effect::DIM, + ..Attr::default() + }; + + assert_eq!(Some(('h', attr)), it.next()); + assert_eq!(Some(('i', attr)), it.next()); + assert_eq!(None, it.next()); + assert_eq!(ansistring.stripped(), "hi"); + } } diff --git a/skim/src/engine/fuzzy.rs b/skim/src/engine/fuzzy.rs index 82b0a5e3..21f97f81 100644 --- a/skim/src/engine/fuzzy.rs +++ b/skim/src/engine/fuzzy.rs @@ -1,3 +1,4 @@ +use std::cmp::min; use std::fmt::{Display, Error, Formatter}; use std::sync::Arc; @@ -9,7 +10,6 @@ use fuzzy_matcher::FuzzyMatcher; use crate::item::RankBuilder; use crate::{CaseMatching, MatchEngine}; use crate::{MatchRange, MatchResult, SkimItem}; -use bitflags::_core::cmp::min; //------------------------------------------------------------------------------ #[derive(ValueEnum, Debug, Copy, Clone, Default)] diff --git a/skim/src/event.rs b/skim/src/event.rs index 45821bb8..c4825a1a 100644 --- a/skim/src/event.rs +++ b/skim/src/event.rs @@ -1,6 +1,5 @@ // All the events that will be used -use bitflags::bitflags; use std::sync::mpsc::{Receiver, Sender}; use tuikit::key::Key; @@ -77,12 +76,10 @@ pub enum Event { __Nonexhaustive, } -bitflags! { - /// `Effect` is the effect of a text - pub struct UpdateScreen: u8 { - const REDRAW = 0b0000_0001; - const DONT_REDRAW = 0b0000_0010; - } +/// `Effect` is the effect of a text +pub enum UpdateScreen { + Redraw, + DontRedraw, } pub trait EventHandler { diff --git a/skim/src/header.rs b/skim/src/header.rs index f66aa248..3d2c1396 100644 --- a/skim/src/header.rs +++ b/skim/src/header.rs @@ -141,6 +141,6 @@ impl Widget for Header { impl EventHandler for Header { fn handle(&mut self, _event: &Event) -> UpdateScreen { - UpdateScreen::DONT_REDRAW + UpdateScreen::DontRedraw } } diff --git a/skim/src/input.rs b/skim/src/input.rs index 92cd0790..bf346751 100644 --- a/skim/src/input.rs +++ b/skim/src/input.rs @@ -170,8 +170,8 @@ fn get_default_key_map() -> HashMap { ret.insert(Key::CtrlRight, vec![Event::EvActForwardWord]); ret.insert(Key::ShiftRight, vec![Event::EvActForwardWord]); ret.insert(Key::Alt('d'), vec![Event::EvActKillWord]); - ret.insert(Key::ShiftUp, vec![Event::EvActPreviewPageUp(1)]); - ret.insert(Key::ShiftDown, vec![Event::EvActPreviewPageDown(1)]); + ret.insert(Key::ShiftUp, vec![Event::EvActPreviewUp(1)]); + ret.insert(Key::ShiftDown, vec![Event::EvActPreviewDown(1)]); ret.insert(Key::PageDown, vec![Event::EvActPageDown(1)]); ret.insert(Key::PageUp, vec![Event::EvActPageUp(1)]); ret.insert(Key::Ctrl('r'), vec![Event::EvActRotateMode]); diff --git a/skim/src/previewer.rs b/skim/src/previewer.rs index 304cba40..1a08fe13 100644 --- a/skim/src/previewer.rs +++ b/skim/src/previewer.rs @@ -333,9 +333,9 @@ impl EventHandler for Previewer { EvActPreviewRight(diff) => self.act_scroll_right(*diff), EvActPreviewPageUp(diff) => self.act_scroll_down(-(height as i32 * *diff)), EvActPreviewPageDown(diff) => self.act_scroll_down(height as i32 * *diff), - _ => return UpdateScreen::DONT_REDRAW, + _ => return UpdateScreen::DontRedraw, } - UpdateScreen::REDRAW + UpdateScreen::Redraw } } diff --git a/skim/src/query.rs b/skim/src/query.rs index 524b1def..d22c8e7a 100644 --- a/skim/src/query.rs +++ b/skim/src/query.rs @@ -534,9 +534,9 @@ impl EventHandler for Query { } if self.query_changed(mode, query_before_len, query_after_len, cmd_before_len, cmd_after_len) { - UpdateScreen::REDRAW + UpdateScreen::Redraw } else { - UpdateScreen::DONT_REDRAW + UpdateScreen::DontRedraw } } } diff --git a/skim/src/selection.rs b/skim/src/selection.rs index 8f02e40b..4f80d5df 100644 --- a/skim/src/selection.rs +++ b/skim/src/selection.rs @@ -417,9 +417,9 @@ impl EventHandler for Selection { EvActScrollRight(diff) => { self.act_scroll(*diff); } - _ => return UpdateScreen::DONT_REDRAW, + _ => return UpdateScreen::DontRedraw, } - UpdateScreen::REDRAW + UpdateScreen::Redraw } }