├── .gitignore ├── zsh-histdb-skim.plugin.zsh ├── src ├── location.rs ├── focus.rs ├── title.rs ├── environment.rs ├── history.rs ├── query.rs └── main.rs ├── Cargo.toml ├── zsh-histdb-skim-vendored.zsh ├── LICENSE ├── .drone.jsonnet ├── zsh-histdb-skim.zsh ├── tests └── create_test_db.sh ├── README.md ├── .github └── workflows │ ├── check.yml │ └── rust.yml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /zsh-histdb-skim.plugin.zsh: -------------------------------------------------------------------------------- 1 | zsh-histdb-skim.zsh -------------------------------------------------------------------------------- /src/location.rs: -------------------------------------------------------------------------------- 1 | use enum_map::Enum; 2 | 3 | #[derive(PartialEq, Enum, Copy, Clone)] 4 | pub enum Location { 5 | Session, 6 | Directory, 7 | Machine, 8 | Everywhere, 9 | } 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zsh-histdb-skim" 3 | version = "0.9.6" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | skim = { version = "0.10.4", default-features = false } 10 | rusqlite = "0.28.0" 11 | tuikit = "0.5.0" 12 | chrono = "0.4.38" 13 | enum-map = "2.7.3" 14 | log = "0.4" 15 | textwrap = "0.15" 16 | humantime = "2.1.0" 17 | once_cell = "1.19.0" 18 | 19 | [dev-dependencies] 20 | regex = "*" 21 | -------------------------------------------------------------------------------- /zsh-histdb-skim-vendored.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | histdb-skim-widget() { 4 | origquery=${BUFFER} 5 | output=$( \ 6 | HISTDB_HOST=${HISTDB_HOST:-"'$(sql_escape ${HOST})'"} \ 7 | HISTDB_SESSION=$HISTDB_SESSION \ 8 | HISTDB_FILE=$HISTDB_FILE \ 9 | zsh-histdb-skim "$origquery"\ 10 | ) 11 | 12 | if [ $? -eq 0 ]; then 13 | BUFFER=$output 14 | else 15 | BUFFER=$origquery 16 | fi 17 | 18 | CURSOR=$#BUFFER 19 | zle redisplay 20 | } 21 | 22 | zle -N histdb-skim-widget 23 | bindkey '^R' histdb-skim-widget 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Matthias Bilger 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/focus.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::sync::{Mutex, MutexGuard}; 3 | 4 | struct AppState { 5 | focus_session: Option, 6 | focus_dir: Option, 7 | } 8 | static APP_STATE: Lazy> = Lazy::new(|| { 9 | Mutex::new(AppState { 10 | focus_session: None, 11 | focus_dir: None, 12 | }) 13 | }); 14 | 15 | fn access_app_state() -> MutexGuard<'static, AppState> { 16 | APP_STATE.lock().unwrap() 17 | } 18 | 19 | pub fn focus_session(session: &str) { 20 | let mut app_state = access_app_state(); 21 | app_state.focus_session = Some(session.to_string()); 22 | } 23 | 24 | pub fn get_focus_session() -> Option { 25 | let app_state = access_app_state(); 26 | return match app_state.focus_session.as_ref() { 27 | Some(v) => return Some(v.to_string()), 28 | None => None, 29 | }; 30 | } 31 | 32 | pub fn reset_focus_session() { 33 | let mut app_state = access_app_state(); 34 | app_state.focus_session = None; 35 | } 36 | 37 | pub fn focus_dir(dir: &str) { 38 | let mut app_state = access_app_state(); 39 | app_state.focus_dir = Some(dir.to_string()); 40 | } 41 | 42 | pub fn get_focus_dir() -> Option { 43 | let app_state = access_app_state(); 44 | return match app_state.focus_dir.as_ref() { 45 | Some(v) => return Some(v.to_string()), 46 | None => None, 47 | }; 48 | } 49 | 50 | pub fn reset_focus_dir() { 51 | let mut app_state = access_app_state(); 52 | app_state.focus_dir = None; 53 | } 54 | -------------------------------------------------------------------------------- /.drone.jsonnet: -------------------------------------------------------------------------------- 1 | local Pipeline(name, version) = { 2 | kind: "pipeline", 3 | type: "docker", 4 | name: name, 5 | steps: [ 6 | { 7 | name: "build", 8 | image: "rust:" + version, 9 | pull: "if-not-exists", 10 | commands: [ 11 | "cargo build --verbose --all --release", 12 | "mkdir -p dist", 13 | "cp target/release/zsh-histdb-skim dist/zsh-histdb-skim-linux-x64", 14 | ] 15 | }, 16 | { 17 | name: "build darwin", 18 | image: "joseluisq/rust-linux-darwin-builder:" + version, 19 | pull: "if-not-exists", 20 | commands: [ 21 | "cargo build --verbose --all --release --target x86_64-apple-darwin", 22 | "mkdir -p dist", 23 | "cp target/x86_64-apple-darwin/release/zsh-histdb-skim dist/zsh-histdb-skim-darwin-x64", 24 | "cargo test --verbose --all" 25 | ] 26 | }, 27 | { 28 | name: "release", 29 | image: "alpine:latest", 30 | pull: "if-not-exists", 31 | environment:{ 32 | GH_TOKEN: { 33 | from_secret: "github_release", 34 | }, 35 | }, 36 | commands: [ 37 | "echo $GH_TOKEN", 38 | "export GH_REPO=m42e/zsh-histdb-skim", 39 | "apk --no-cache add wget tar", 40 | "wget https://github.com/cli/cli/releases/download/v2.6.0/gh_2.6.0_linux_amd64.tar.gz", 41 | "tar -zxvf gh_2.6.0_linux_amd64.tar.gz", 42 | "chmod a+x gh_2.6.0_linux_amd64/bin/gh", 43 | "gh_2.6.0_linux_amd64/bin/gh release create --target ${DRONE_COMMIT} ${DRONE_TAG} dist/*", 44 | ], 45 | when: { 46 | event: 'tag' 47 | }, 48 | } 49 | ] 50 | }; 51 | 52 | [ 53 | Pipeline("rust-1-68", "1.68"), 54 | ] 55 | -------------------------------------------------------------------------------- /zsh-histdb-skim.zsh: -------------------------------------------------------------------------------- 1 | XDG_BIN_PATH=${XDG_DATA_HOME:-$HOME/.local/share}/zsh-histdb-skim/ 2 | BIN_DIR=${HISTDB_SKIM_PATH:-${XDG_BIN_PATH}} 3 | BIN_PATH=${BIN_DIR}/zsh-histdb-skim 4 | 5 | HISTB_SKIM_VERSION="v0.9.6" 6 | 7 | histdb-skim-get-os(){ 8 | UNAME_STR=`uname -a` 9 | if [[ ( $UNAME_STR =~ '.*Darwin.*' ) && ( $UNAME_STR =~ '.*x86_64.*') ]]; then 10 | echo -n "darwin-x64" 11 | fi 12 | if [[ ( $UNAME_STR =~ '.*Darwin.*' ) && ( $UNAME_STR =~ '.*arm64.*') ]]; then 13 | echo -n "darwin-arm" 14 | fi 15 | if [[ ( $UNAME_STR =~ '.*Linux.*' ) && ( $UNAME_STR =~ '.*x86_64.*') ]]; then 16 | echo -n "linux-x64" 17 | fi 18 | } 19 | 20 | histdb-skim-get-latest-version(){ 21 | curl -s https://github.com/m42e/zsh-histdb-skim/releases/latest | grep --color=never -o 'v[0-9]*\.[0-9]*\.[0-9]*' 22 | } 23 | 24 | histdb-skim-download(){ 25 | if [[ -z $(histdb-skim-get-os) ]]; then 26 | echo "Could not find prebuild executable" 27 | echo "Sorry, you have to do it yourself" 28 | else 29 | echo "Downloading binary" 30 | mkdir -p ${BIN_DIR} 31 | curl -s -JL https://github.com/m42e/zsh-histdb-skim/releases/download/${HISTB_SKIM_VERSION}/zsh-histdb-skim-$(histdb-skim-get-os) -o ${BIN_PATH} 32 | chmod +x ${BIN_PATH} 33 | fi 34 | } 35 | 36 | histdb-skim-ensure () { 37 | if [[ ! -f ${BIN_PATH} || $(${BIN_PATH} --version) != ${HISTB_SKIM_VERSION} ]]; then 38 | if command -v cargo &> /dev/null; then 39 | echo "cargo is available, starting Rust release build" 40 | SOURCE="${(%):-%x}" 41 | SCRIPT_DIR=$(cd "$(dirname "$SOURCE")" && pwd) 42 | (cd ${SCRIPT_DIR};\ 43 | cargo build --release --manifest-path "${SCRIPT_DIR}/Cargo.toml" && \ 44 | cp "${SCRIPT_DIR}/target/release/zsh-histdb-skim" ${BIN_PATH}) 45 | else 46 | histdb-skim-download 47 | fi 48 | fi 49 | } 50 | 51 | histdb-skim-widget() { 52 | origquery=${BUFFER} 53 | output=$( \ 54 | HISTDB_HOST=${HISTDB_HOST:-"'$(sql_escape ${HOST})'"} \ 55 | HISTDB_SESSION=$HISTDB_SESSION \ 56 | HISTDB_FILE=$HISTDB_FILE \ 57 | ${BIN_PATH} "$origquery"\ 58 | ) 59 | 60 | if [ $? -eq 0 ]; then 61 | BUFFER=$output 62 | else 63 | BUFFER=$origquery 64 | fi 65 | 66 | CURSOR=$#BUFFER 67 | zle redisplay 68 | } 69 | 70 | histdb-skim-ensure 71 | 72 | zle -N histdb-skim-widget 73 | bindkey '^R' histdb-skim-widget 74 | -------------------------------------------------------------------------------- /tests/create_test_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | _histdb_query () { 3 | sqlite3 -batch -noheader -cmd ".timeout 1000" "test.db" "$@" 4 | [[ "$?" -ne 0 ]] && echo "error in $@" 5 | } 6 | echo "Create Tables" 7 | _histdb_query <<-EOF 8 | create table commands (id integer primary key autoincrement, argv text, unique(argv) on conflict ignore); 9 | create table places (id integer primary key autoincrement, host text, dir text, unique(host, dir) on conflict ignore); 10 | create table history (id integer primary key autoincrement, 11 | session int, 12 | command_id int references commands (id), 13 | place_id int references places (id), 14 | exit_status int, 15 | start_time int, 16 | duration int); 17 | PRAGMA user_version = 2 18 | EOF 19 | 20 | echo "Create index" 21 | _histdb_query<<-EOF 22 | create index if not exists hist_time on history(start_time); 23 | create index if not exists place_dir on places(dir); 24 | create index if not exists place_host on places(host); 25 | create index if not exists history_command_place on history(command_id, place_id); 26 | PRAGMA journal_mode = WAL; 27 | PRAGMA synchronous=normal; 28 | EOF 29 | 30 | insert_data(){ 31 | cmd=$1 32 | pwd=$2 33 | host=$3 34 | session=$4 35 | started=$5 36 | 37 | _histdb_query <<-EOF 38 | insert into commands (argv) values ('${cmd}'); 39 | insert into places (host, dir) values ('${host}', '${pwd}'); 40 | insert into history 41 | (session, command_id, place_id, start_time) 42 | select 43 | ${session}, 44 | commands.id, 45 | places.id, 46 | ${started} 47 | from 48 | commands, places 49 | where 50 | commands.argv = '${cmd}' and 51 | places.host = '${host}' and 52 | places.dir = '${pwd}' 53 | ; 54 | EOF 55 | } 56 | 57 | echo "Inserting fake test data" 58 | insert_data "echo second" "$(pwd)" "testhost" "4713" 1640995210 59 | insert_data "echo first" "$(pwd)" "testhost" "4713" 1640995209 60 | insert_data "echo second" "/home/someone/skripts" "testhost" "4711" $(date +%s) 61 | insert_data "echo first" "/home/someone/skripts" "testhost" "4711" 1640995201 62 | 63 | insert_data "echo second2" "/home/someone/skripts" "testhost" "4712" $(date +%s) 64 | insert_data "echo first2" "/home/someone/skripts" "testhost" "4712" 1640995202 65 | 66 | insert_data "echo tmp" "/tmp" "otherhost" "12" 1640995205 67 | -------------------------------------------------------------------------------- /src/title.rs: -------------------------------------------------------------------------------- 1 | use crate::environment::*; 2 | use crate::focus::get_focus_dir; 3 | use crate::focus::get_focus_session; 4 | use crate::location::Location; 5 | use enum_map::enum_map; 6 | 7 | pub fn generate_title(location: &Location) -> String { 8 | let extra_info = |theloc: &Location| -> String { 9 | return match theloc { 10 | Location::Session => get_current_session_id(), 11 | Location::Directory => get_current_dir(), 12 | Location::Machine => get_current_host(), 13 | _ => String::from(""), 14 | }; 15 | }(&location); 16 | 17 | let format_extra_info = |info: Option, title: &str| -> String { 18 | return match info { 19 | Some(ri) => format!("{}: {} ", &title, &ri,), 20 | None => String::from(""), 21 | }; 22 | }; 23 | let focus_session = format_extra_info(get_focus_session(), "Session"); 24 | let focus_dir = format_extra_info(get_focus_dir(), "Directory"); 25 | 26 | let location_map = enum_map! { 27 | Location::Session => "Session location history", 28 | Location::Directory => "Directory location history", 29 | Location::Machine => "Machine location history", 30 | Location::Everywhere => "Everywhere", 31 | }; 32 | 33 | let header_map = enum_map! { 34 | Location::Session => 35 | " ┏━━━━━━━━━━━┱─────────────┬────────┬──────────────┐ 36 | ┃F1: Session┃F2: Directory│F3: Host│F4: Everywhere│ F5: Toggle group, F6: Lock Session, F7: Lock Dir 37 | ━┛ ┗━━━━━━━━━━━━━┷━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 38 | Location::Directory => 39 | " ┌───────────┲━━━━━━━━━━━━━┱────────┬──────────────┐ 40 | │F1: Session┃F2: Directory┃F3: Host│F4: Everywhere│ F5: Toggle group, F6: Lock Session, F7: Lock Dir 41 | ━┷━━━━━━━━━━━┛ ┗━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 42 | 43 | Location::Machine => 44 | " ┌───────────┬─────────────┲━━━━━━━━┱──────────────┐ 45 | │F1: Session│F2: Directory┃F3: Host┃F4: Everywhere│ F5: Toggle group, F6: Lock Session, F7: Lock Dir 46 | ━┷━━━━━━━━━━━┷━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 47 | 48 | Location::Everywhere => 49 | " ┌───────────┬─────────────┬────────┲━━━━━━━━━━━━━━┓ 50 | │F1: Session│F2: Directory│F3: Host┃F4: Everywhere┃ F5: Toggle group, F6: Lock Session, F7: Lock Dir 51 | ━┷━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", 52 | }; 53 | 54 | let title = format!( 55 | "{} {} {}{}\n{}\n", 56 | &location_map[location.clone()], 57 | &extra_info, 58 | &focus_session, 59 | &focus_dir, 60 | &header_map[location.clone()], 61 | ); 62 | return title.to_string(); 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zsh-histdb-skim 2 | 3 | This is a reimplementation of https://github.com/m42e/zsh-histdb-fzf in rust and using skim as a library. 4 | 5 | ## Why 6 | 7 | [zsh-histdb-fzf](https://github.com/m42e/zsh-histdb-fzf) works, but it is a bit quirky. It has for sure some flaws, regarding responsiveness and communication with processes. 8 | [skim](https://github.com/lotabout/skim) offers a fzf like behavior and is available as library in rust. It lacks some highlighting in the header, and has a bit different order/matching algorithm. 9 | 10 | This should result in better performance, responsiveness and a more stable behavior. 11 | 12 | ## Why rust? 13 | 14 | [skim](https://github.com/lotabout/skim) is available in rust. I have never tried rust with a purpose before. I wanted to give it a try and learn something new. 15 | 16 | ## How it works 17 | 18 | Well, it accesses the [zsh histdb](https://github.com/larkery/zsh-histdb). It lets you search on different levels. 19 | 20 | ## What do you have to do? 21 | 22 | Install the plugin, e.g. using [zplug](https://github.com/zplug/zplug). 23 | 24 | ``` 25 | zplug 'm42e/zsh-histdb-skim', from:github, at:main 26 | ``` 27 | 28 | It downloads the binary (if available) automatically. You can do manually by calling `histdb-skim-download`. It will be saved in `${XDG_DATA_HOME}/zsh-histdb-skim`, alternatively `${HOME}/.local/share/zsh-histdb-skim`. You can specify the directory manually by setting `HISTDB_SKIM_PATH`. 29 | 30 | The download will happen if the executable is not there or the version is outdated (starting from v0.7.0). These checks happen when sourcing the script. 31 | 32 | 33 | The plugin calls `bindkey` but some other plugins may overwrite. In this case you would have to do it yourself: 34 | 35 | ``` 36 | bindkey '^R' histdb-skim-widget 37 | ``` 38 | 39 | 40 | ## Additional information 41 | 42 | By default the binary is downloaded 43 | 44 | 45 | ## Building 46 | 47 | ``` 48 | cargo build --release 49 | mkdir -p bin 50 | mv target/release/zsh-histdb-skim bin 51 | ``` 52 | 53 | ## Environment Variables 54 | 55 | - **HISTDB_FZF_FORCE_DATE_FORMAT**: You can force us or non-us time format. 56 | - **HISTDB_FILE**: SQLite file, having all the commands. (is set by zsh-histdb) 57 | - **HISTDB_SESSION**: The current session id (is set by zsh-histdb) 58 | - **HISTDB_HOST**: The current hostname (is set by zsh-histdb) 59 | - **HISTDB_NOSORT**: Do not sort within skim. If set, the order of the commands is kept 60 | - **HISTDB_PREVIEW**: This defines the format/position of the preview window. `[POSITION][:SIZE[%]][:wrap][:hidden][:+SCROLL[-OFFSET]]` 61 | - **HISTDB_DEFAULT_TAB**: Set the default tab. Directory|Machine or Host|Everything or *|Session (any non matching value will be treated as Session) 62 | 63 | # TODO 64 | - improve rust code 65 | 66 | # Apologies 😉 67 | 68 | While I stole the idea from myself, this is my first rust project ever. So I would be glad for tips and improvement PRs. 69 | -------------------------------------------------------------------------------- /src/environment.rs: -------------------------------------------------------------------------------- 1 | use crate::location::Location; 2 | use std::env; 3 | 4 | /// Get the default (which is non us! or the us date format) 5 | /// - [ ] Read from locale to determine default 6 | pub fn get_date_format() -> String { 7 | let key = "HISTDB_FZF_FORCE_DATE_FORMAT"; 8 | let forced_dateformat = env::var(key).unwrap_or("non-us".to_string()).to_lowercase(); 9 | 10 | if forced_dateformat == "us" { 11 | return "%m/%d/%Y".to_string(); 12 | } else { 13 | return "%d/%m/%Y".to_string(); 14 | } 15 | } 16 | 17 | /// Get the histdb file from the environment 18 | pub fn get_histdb_database() -> String { 19 | let key = "HISTDB_FILE"; 20 | let db_file = env::var(key).unwrap_or(String::from("")); 21 | return db_file.to_string(); 22 | } 23 | 24 | /// Get the histdb session from the environment 25 | pub fn get_current_session_id() -> String { 26 | let key = "HISTDB_SESSION"; 27 | let session_id = env::var(key).unwrap_or(String::from("")); 28 | return session_id.to_string(); 29 | } 30 | 31 | /// Get the current working directory 32 | pub fn get_current_dir() -> String { 33 | let current_dir = env::current_dir().unwrap(); 34 | let cdir_string = current_dir.to_str().unwrap(); 35 | return cdir_string.to_string(); 36 | } 37 | 38 | /// Get the current histdb host from the environment 39 | pub fn get_current_host() -> String { 40 | let mut host = env::var("HISTDB_HOST").unwrap_or(String::from("")); 41 | if host.starts_with("'") && host.ends_with("'") { 42 | host = host[1..host.len() - 1].to_string() 43 | } 44 | return host.to_string(); 45 | } 46 | 47 | /// Disable sorting so history would be kept in historical order 48 | pub fn get_nosort_option() -> bool { 49 | let nosort = env::var("HISTDB_NOSORT").unwrap_or(String::from("false")); 50 | if nosort.to_lowercase() == "true" || nosort == "1" { 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | /// Configure preview window option [POSITION][:SIZE[%]][:wrap][:hidden][:+SCROLL[-OFFSET]] 57 | pub fn get_preview_window_option() -> String { 58 | let window = env::var("HISTDB_PREVIEW").unwrap_or(String::from("right:50%:true:false")); 59 | return window.to_string(); 60 | } 61 | 62 | /// Configure preview window option [POSITION][:SIZE[%]][:wrap][:hidden][:+SCROLL[-OFFSET]] 63 | pub fn get_default_tab() -> Location { 64 | let default_tab = env::var("HISTDB_DEFAULT_TAB") 65 | .unwrap_or(String::from("Session")) 66 | .to_lowercase(); 67 | match default_tab.as_str() { 68 | "directory" => Location::Directory, 69 | "machine" => Location::Machine, 70 | "host" => Location::Machine, 71 | "everywhere" => Location::Everywhere, 72 | "*" => Location::Everywhere, 73 | _ => Location::Session, 74 | } 75 | } 76 | 77 | pub fn get_color() -> String { 78 | let color = env::var("HISTDB_COLOR").unwrap_or(String::from("auto")); 79 | return color.to_string(); 80 | } 81 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Rust check 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '**' 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | rustfmt: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | - run: rustup component add rustfmt 17 | - run: cargo fmt -- --check 18 | 19 | build: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v1 25 | # cache the build assets so they dont recompile every time. 26 | - name: Cache Rust dependencies 27 | uses: actions/cache@v1.0.1 28 | with: 29 | path: target 30 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 31 | restore-keys: | 32 | ${{ runner.OS }}-build- 33 | - name: Install latest rust toolchain 34 | uses: actions-rs/toolchain@v1 35 | with: 36 | toolchain: stable 37 | default: true 38 | override: true 39 | - name: Target 40 | run: rustup target add x86_64-unknown-linux-musl 41 | 42 | - name: Install system dependencies 43 | run: | 44 | sudo apt-get update \ 45 | && sudo apt-get install -y \ 46 | libdbus-1-dev 47 | - name: Build 48 | run: cargo build --all --release --target x86_64-unknown-linux-musl && strip target/x86_64-unknown-linux-musl/release/zsh-histdb-skim 49 | 50 | build-mac-intel: 51 | runs-on: macos-latest 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v1 56 | - name: Cache Rust dependencies 57 | uses: actions/cache@v1.0.1 58 | with: 59 | path: target 60 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 61 | restore-keys: | 62 | ${{ runner.OS }}-build- 63 | - name: Install latest rust toolchain 64 | uses: actions-rs/toolchain@v1 65 | with: 66 | toolchain: stable 67 | target: x86_64-apple-darwin 68 | default: true 69 | override: true 70 | 71 | - name: Build for mac 72 | run: cargo build --all --release --target x86_64-apple-darwin && strip target/x86_64-apple-darwin/release/zsh-histdb-skim 73 | 74 | build-mac-arm: 75 | runs-on: macos-latest 76 | 77 | steps: 78 | - name: Checkout 79 | uses: actions/checkout@v1 80 | - name: Cache Rust dependencies 81 | uses: actions/cache@v1.0.1 82 | with: 83 | path: target 84 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 85 | restore-keys: | 86 | ${{ runner.OS }}-build- 87 | - name: Install latest rust toolchain 88 | uses: actions-rs/toolchain@v1 89 | with: 90 | toolchain: stable 91 | target: aarch64-apple-darwin 92 | default: true 93 | override: true 94 | 95 | - name: Build for mac 96 | run: cargo build --all --release && strip target/release/zsh-histdb-skim 97 | 98 | -------------------------------------------------------------------------------- /src/history.rs: -------------------------------------------------------------------------------- 1 | extern crate skim; 2 | use crate::environment::*; 3 | use chrono::{DateTime, Local, TimeZone}; 4 | use humantime::format_duration; 5 | use skim::prelude::*; 6 | use std::time::Duration; 7 | use std::time::SystemTime; 8 | use textwrap::fill; 9 | 10 | fn get_epoch_start_of_day() -> u64 { 11 | let now = SystemTime::now(); 12 | let now_secs = now 13 | .duration_since(SystemTime::UNIX_EPOCH) 14 | .unwrap_or_default() 15 | .as_secs(); 16 | 17 | let seconds_since_midnight = now_secs % (24 * 3600); 18 | now_secs - seconds_since_midnight 19 | } 20 | 21 | pub struct History { 22 | pub id: i64, 23 | pub cmd: String, 24 | pub start: u64, 25 | pub exit_status: Option, 26 | pub duration: Option, 27 | pub count: i64, 28 | pub session: i64, 29 | pub host: String, 30 | pub dir: String, 31 | pub searchrange: [(usize, usize); 1], 32 | } 33 | 34 | impl History { 35 | pub const FORMAT_DATE_LENGTH: usize = 10; 36 | pub const COMMAND_START: usize = (History::FORMAT_DATE_LENGTH + 1); 37 | 38 | pub fn command(&self) -> &String { 39 | return &self.cmd; 40 | } 41 | pub fn session(&self) -> String { 42 | return self.session.to_string(); 43 | } 44 | pub fn dir(&self) -> String { 45 | return self.dir.to_string(); 46 | } 47 | } 48 | 49 | impl History { 50 | fn format_date(&self, full: bool) -> String { 51 | let starttime: DateTime = Local.timestamp_opt(self.start as i64, 0).unwrap(); 52 | if full { 53 | let mut dateinfo = String::from(""); 54 | dateinfo.push_str(&get_date_format()); 55 | dateinfo.push_str(" %H:%M"); 56 | return format!("{}", starttime.format(&dateinfo)); 57 | } else if self.start > get_epoch_start_of_day() { 58 | return format!("{}", starttime.format("%H:%M")); 59 | } else { 60 | return format!("{}", starttime.format(&get_date_format())); 61 | } 62 | } 63 | 64 | fn format_or_none(x: Option) -> String { 65 | if x.is_some() { 66 | format!("{}", x.unwrap()) 67 | } else { 68 | "\x1b[37;1m\x1b[0m".to_string() 69 | } 70 | } 71 | 72 | fn format_duration(&self) -> String { 73 | if self.duration.is_some() { 74 | let duration = Duration::from_secs(self.duration.unwrap() as u64); 75 | format_duration(duration).to_string() 76 | } else { 77 | History::format_or_none(self.duration) 78 | } 79 | } 80 | } 81 | 82 | impl SkimItem for History { 83 | fn text(&self) -> Cow { 84 | let information = format!("{:10} {}", self.format_date(false), self.cmd); 85 | Cow::Owned(information) 86 | } 87 | 88 | fn preview(&self, _context: PreviewContext) -> ItemPreview { 89 | let mut information = String::from(format!("\x1b[1mDetails for {}\x1b[0m\n\n", self.id)); 90 | 91 | let mut tformat = |name: &str, value: &str| { 92 | information.push_str(&format!("\x1b[1m{:20}\x1b[0m{}\n", name, value)); 93 | }; 94 | 95 | tformat("Runtime", &self.format_duration()); 96 | tformat("Host", &self.host); 97 | tformat("Executed", &self.count.to_string()); 98 | tformat("Directory", &self.dir); 99 | tformat("Exit Status", &History::format_or_none(self.exit_status)); 100 | tformat("Session", &self.session.to_string()); 101 | tformat("Start Time", &self.format_date(false)); 102 | information.push_str(&format!( 103 | "\x1b[1mCommand\x1b[0m\n\n{}\n", 104 | &fill(&self.cmd, _context.width) 105 | )); 106 | ItemPreview::AnsiText(information) 107 | } 108 | 109 | fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> { 110 | Some(&self.searchrange) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v** 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | rustfmt: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | - run: rustup component add rustfmt 17 | - run: cargo fmt -- --check 18 | 19 | build: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v1 25 | # cache the build assets so they dont recompile every time. 26 | - name: Cache Rust dependencies 27 | uses: actions/cache@v1.0.1 28 | with: 29 | path: target 30 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 31 | restore-keys: | 32 | ${{ runner.OS }}-build- 33 | - name: Install latest rust toolchain 34 | uses: actions-rs/toolchain@v1 35 | with: 36 | toolchain: stable 37 | default: true 38 | override: true 39 | - name: Target 40 | run: rustup target add x86_64-unknown-linux-musl 41 | 42 | - name: Install system dependencies 43 | run: | 44 | sudo apt-get update \ 45 | && sudo apt-get install -y \ 46 | libdbus-1-dev 47 | - name: Build 48 | run: cargo build --all --release --target x86_64-unknown-linux-musl && strip target/x86_64-unknown-linux-musl/release/zsh-histdb-skim 49 | 50 | - name: Upload binaries to release 51 | uses: svenstaro/upload-release-action@v2 52 | with: 53 | repo_token: ${{ secrets.GITHUB_TOKEN }} 54 | file: target/x86_64-unknown-linux-musl/release/zsh-histdb-skim 55 | asset_name: zsh-histdb-skim-linux-x64 56 | tag: ${{ github.ref }} 57 | overwrite: true 58 | 59 | build-mac-intel: 60 | runs-on: macos-latest 61 | 62 | steps: 63 | - name: Checkout 64 | uses: actions/checkout@v1 65 | - name: Cache Rust dependencies 66 | uses: actions/cache@v1.0.1 67 | with: 68 | path: target 69 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 70 | restore-keys: | 71 | ${{ runner.OS }}-build- 72 | - name: Install latest rust toolchain 73 | uses: actions-rs/toolchain@v1 74 | with: 75 | toolchain: stable 76 | target: x86_64-apple-darwin 77 | default: true 78 | override: true 79 | 80 | - name: Build for mac 81 | run: cargo build --all --release --target x86_64-apple-darwin && strip target/x86_64-apple-darwin/release/zsh-histdb-skim 82 | 83 | - name: Upload binaries to release 84 | uses: svenstaro/upload-release-action@v2 85 | with: 86 | repo_token: ${{ secrets.GITHUB_TOKEN }} 87 | file: target/x86_64-apple-darwin/release/zsh-histdb-skim 88 | asset_name: zsh-histdb-skim-darwin-x64 89 | tag: ${{ github.ref }} 90 | overwrite: true 91 | 92 | build-mac-arm: 93 | runs-on: macos-latest 94 | 95 | steps: 96 | - name: Checkout 97 | uses: actions/checkout@v1 98 | - name: Cache Rust dependencies 99 | uses: actions/cache@v1.0.1 100 | with: 101 | path: target 102 | key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }} 103 | restore-keys: | 104 | ${{ runner.OS }}-build- 105 | - name: Install latest rust toolchain 106 | uses: actions-rs/toolchain@v1 107 | with: 108 | toolchain: stable 109 | target: aarch64-apple-darwin 110 | default: true 111 | override: true 112 | 113 | - name: Build for mac 114 | run: cargo build --all --release && strip target/release/zsh-histdb-skim 115 | 116 | - name: Upload binaries to release 117 | uses: svenstaro/upload-release-action@v2 118 | with: 119 | repo_token: ${{ secrets.GITHUB_TOKEN }} 120 | file: target/release/zsh-histdb-skim 121 | asset_name: zsh-histdb-skim-darwin-aarch64 122 | tag: ${{ github.ref }} 123 | overwrite: true 124 | 125 | -------------------------------------------------------------------------------- /src/query.rs: -------------------------------------------------------------------------------- 1 | use crate::environment::*; 2 | use crate::focus::get_focus_dir; 3 | use crate::focus::get_focus_session; 4 | use crate::location::Location; 5 | 6 | pub fn build_query_string(theloc: &Location, grouped: bool) -> String { 7 | let mut query = String::from("select history.id as id, commands.argv as cmd,"); 8 | if !grouped { 9 | query.push_str(" start_time") 10 | } else { 11 | query.push_str(" max(start_time)") 12 | } 13 | query.push_str(" as start, exit_status, duration,"); 14 | if !grouped { 15 | query.push_str(" 1") 16 | } else { 17 | query.push_str(" count()") 18 | } 19 | query.push_str(" as count, history.session as session, places.host as host, places.dir as dir"); 20 | query.push_str(" from history"); 21 | query.push_str(" left join commands on history.command_id = commands.id"); 22 | query.push_str(" left join places on history.place_id = places.id"); 23 | match theloc { 24 | Location::Session | Location::Directory | Location::Machine => { 25 | query.push_str(" where"); 26 | } 27 | _ => {} 28 | }; 29 | match theloc { 30 | Location::Session => { 31 | let session = get_focus_session().unwrap_or(get_current_session_id()); 32 | query.push_str(&format!(" session == {} and", session)); 33 | } 34 | 35 | Location::Directory => { 36 | let session = get_focus_dir().unwrap_or(get_current_dir()); 37 | query.push_str(&format!(" places.dir like '{}' and", session)); 38 | } 39 | 40 | _ => {} 41 | }; 42 | match theloc { 43 | Location::Machine | Location::Everywhere => { 44 | let session = get_focus_session(); 45 | let dir = get_focus_dir(); 46 | if dir.is_some() { 47 | query.push_str(&format!(" places.dir like '{}' and", dir.unwrap())); 48 | } 49 | if session.is_some() { 50 | query.push_str(&format!(" session == {} and", session.unwrap())); 51 | } 52 | } 53 | 54 | _ => {} 55 | }; 56 | match theloc { 57 | Location::Session | Location::Directory | Location::Machine => { 58 | query.push_str(&format!(" places.host == '{}'", &get_current_host())); 59 | } 60 | _ => {} 61 | }; 62 | if grouped { 63 | query.push_str(" group by history.command_id, history.place_id"); 64 | } 65 | query.push_str(" order by start desc"); 66 | return query; 67 | } 68 | 69 | #[cfg(test)] 70 | mod query { 71 | use super::*; 72 | use regex::Regex; 73 | 74 | #[test] 75 | fn has_select_fields() { 76 | for l in vec![ 77 | Location::Session, 78 | Location::Directory, 79 | Location::Machine, 80 | Location::Everywhere, 81 | ] { 82 | let query = build_query_string(&l, true); 83 | assert!(query.contains("history.id as id")); 84 | assert!(query.contains("exit_status")); 85 | assert!(query.contains("start")); 86 | assert!(query.contains("duration")); 87 | assert!(query.contains("count")); 88 | assert!(query.contains("history.session as session")); 89 | assert!(query.contains("places.dir")); 90 | } 91 | } 92 | 93 | #[test] 94 | fn contains_host() { 95 | let re_host = Regex::new(r"host == '.*'").unwrap(); 96 | for l in vec![Location::Session, Location::Directory, Location::Machine] { 97 | let query = build_query_string(&l, true); 98 | assert!(re_host.is_match(&query)); 99 | } 100 | let query = build_query_string(&Location::Everywhere, true); 101 | assert!(!re_host.is_match(&query)); 102 | } 103 | 104 | #[test] 105 | fn contains_grouping() { 106 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 107 | for l in vec![ 108 | Location::Session, 109 | Location::Directory, 110 | Location::Machine, 111 | Location::Everywhere, 112 | ] { 113 | let query = build_query_string(&l, true); 114 | assert!(re_group.is_match(&query)); 115 | } 116 | } 117 | 118 | #[test] 119 | fn contains_no_grouping_if_disabled() { 120 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 121 | let re_only_group = Regex::new(r"group").unwrap(); 122 | for l in vec![ 123 | Location::Session, 124 | Location::Directory, 125 | Location::Machine, 126 | Location::Everywhere, 127 | ] { 128 | let query = build_query_string(&l, false); 129 | assert!(!re_only_group.is_match(&query)); 130 | assert!(!re_group.is_match(&query)); 131 | } 132 | } 133 | 134 | #[test] 135 | fn for_session() { 136 | let query = build_query_string(&Location::Session, true); 137 | let re_session = Regex::new(r"session == (\d*) and").unwrap(); 138 | let re_host = Regex::new(r"host == '.*'").unwrap(); 139 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 140 | assert!(re_session.is_match(&query)); 141 | assert!(re_host.is_match(&query)); 142 | assert!(re_group.is_match(&query)); 143 | } 144 | 145 | #[test] 146 | fn for_directory() { 147 | let query = build_query_string(&Location::Directory, false); 148 | let re_directory = Regex::new(r"places.dir like '.*' and").unwrap(); 149 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 150 | assert!(re_directory.is_match(&query)); 151 | assert!(!re_group.is_match(&query)); 152 | } 153 | 154 | #[test] 155 | fn for_machine() { 156 | let query = build_query_string(&Location::Machine, true); 157 | let re_session = Regex::new(r"session == (\d*) and").unwrap(); 158 | let re_place = Regex::new(r"dir like '.*' and").unwrap(); 159 | let re_host = Regex::new(r"host == '.*'").unwrap(); 160 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 161 | assert!(!re_session.is_match(&query)); 162 | assert!(!re_place.is_match(&query)); 163 | assert!(re_host.is_match(&query)); 164 | assert!(re_group.is_match(&query)); 165 | } 166 | #[test] 167 | fn for_everywhere() { 168 | let query = build_query_string(&Location::Everywhere, true); 169 | let re_session = Regex::new(r"session == (\d*) and").unwrap(); 170 | let re_place = Regex::new(r"dir like '.*' and").unwrap(); 171 | let re_host = Regex::new(r"host == '.*'").unwrap(); 172 | let re_group = Regex::new(r"group by history.command_id, history.place_id").unwrap(); 173 | assert!(!re_session.is_match(&query)); 174 | assert!(!re_place.is_match(&query)); 175 | assert!(!re_host.is_match(&query)); 176 | assert!(re_group.is_match(&query)); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate skim; 2 | mod environment; 3 | mod focus; 4 | mod history; 5 | mod location; 6 | mod query; 7 | mod title; 8 | 9 | use crate::environment::*; 10 | use crate::focus::focus_dir; 11 | use crate::focus::focus_session; 12 | use crate::focus::get_focus_dir; 13 | use crate::focus::get_focus_session; 14 | use crate::focus::reset_focus_dir; 15 | use crate::focus::reset_focus_session; 16 | use crate::history::History; 17 | use crate::location::Location; 18 | use crate::query::build_query_string; 19 | use crate::title::generate_title; 20 | 21 | use rusqlite::{Connection, OpenFlags, Result}; 22 | use skim::prelude::*; 23 | use std::env; 24 | use std::thread; 25 | 26 | fn read_entries(location: &Location, grouped: bool, tx_item: SkimItemSender) { 27 | let conn_res = 28 | Connection::open_with_flags(get_histdb_database(), OpenFlags::SQLITE_OPEN_READ_ONLY); 29 | if conn_res.is_err() { 30 | let _ = tx_item.send(Arc::new("Cannot open database")); 31 | drop(tx_item); 32 | return; 33 | } 34 | let conn = conn_res.unwrap(); 35 | let s = build_query_string(&location, grouped); 36 | 37 | let stmt_result = conn.prepare(&s); 38 | if stmt_result.is_err() { 39 | let _ = tx_item.send(Arc::new(format!( 40 | "Cannot get result from database {}", 41 | stmt_result.err().unwrap() 42 | ))); 43 | drop(tx_item); 44 | return; 45 | } 46 | let mut stmt = stmt_result.unwrap(); 47 | 48 | let cats = stmt.query_map([], |row| { 49 | let cmd: String = row.get("cmd")?; 50 | let commandend = cmd.len() as usize; 51 | Ok(History { 52 | id: row.get("id")?, 53 | cmd: cmd, 54 | start: row.get("start")?, 55 | exit_status: row.get("exit_status")?, 56 | duration: row.get("duration")?, 57 | count: row.get("count")?, 58 | session: row.get("session")?, 59 | host: row.get("host")?, 60 | dir: row.get("dir")?, 61 | searchrange: [( 62 | History::COMMAND_START, 63 | commandend + (History::COMMAND_START), 64 | )], 65 | }) 66 | }); 67 | for person in cats.unwrap() { 68 | if person.is_ok() { 69 | let x = person.unwrap(); 70 | let _ = tx_item.send(Arc::new(x)); 71 | } 72 | } 73 | drop(tx_item); 74 | } 75 | 76 | struct SelectionResult { 77 | selected_cmd: Option, 78 | abort: bool, 79 | } 80 | 81 | fn get_starting_location() -> Location { 82 | let mut location = get_default_tab(); 83 | if location == Location::Session && get_current_session_id() == "" { 84 | location = Location::Directory; 85 | } 86 | location 87 | } 88 | 89 | fn show_history(thequery: String) -> Result { 90 | let mut location = get_starting_location(); 91 | let mut grouped = true; 92 | let mut query = thequery; 93 | loop { 94 | let title = generate_title(&location); 95 | let window_option = get_preview_window_option(); 96 | let color_options = get_color(); 97 | 98 | let options = SkimOptionsBuilder::default() 99 | .height(Some("100%")) 100 | .multi(false) 101 | .reverse(true) 102 | .prompt(Some("history >>")) 103 | .query(Some(&query)) 104 | .color(Some(&color_options)) 105 | .bind(vec![ 106 | "f1:abort", 107 | "f2:abort", 108 | "f3:abort", 109 | "f4:abort", 110 | "f5:abort", 111 | "f6:abort", 112 | "f7:abort", 113 | "ctrl-r:abort", 114 | "ctrl-u:half-page-up", 115 | "ctrl-d:half-page-down", 116 | ]) 117 | .header(Some(&title)) 118 | .preview(Some("")) // preview should be specified to enable preview window 119 | .preview_window(Some(&window_option)) // preview should be specified to enable preview window 120 | .nosort(get_nosort_option()) 121 | .build() 122 | .unwrap(); 123 | 124 | let (tx_item, rx_item): (SkimItemSender, SkimItemReceiver) = unbounded(); 125 | 126 | let handle = thread::spawn(move || { 127 | read_entries(&location, grouped, tx_item); 128 | }); 129 | 130 | let selected_items = Skim::run_with(&options, Some(rx_item)); 131 | handle.join().unwrap(); 132 | 133 | let selection_result = process_result(&selected_items, &mut location, &mut grouped); 134 | if selection_result.abort { 135 | return Err("Aborted".to_string()); 136 | } 137 | if selection_result.selected_cmd.is_some() { 138 | return Ok(selection_result.selected_cmd.unwrap()); 139 | } 140 | query = selected_items.unwrap().query; 141 | } 142 | } 143 | 144 | fn process_result( 145 | selected_items: &Option, 146 | loc: &mut Location, 147 | grouped: &mut bool, 148 | ) -> SelectionResult { 149 | if selected_items.is_some() { 150 | let sel = selected_items.as_ref().unwrap(); 151 | match sel.final_key { 152 | Key::ESC | Key::Ctrl('c') | Key::Ctrl('d') | Key::Ctrl('z') => { 153 | return SelectionResult { 154 | selected_cmd: None, 155 | abort: true, 156 | }; 157 | } 158 | Key::Enter => { 159 | return SelectionResult { 160 | selected_cmd: Some(format!( 161 | "{}", 162 | ((*sel.selected_items[0]).as_any().downcast_ref::()) 163 | .unwrap() 164 | .command() 165 | )), 166 | abort: false, 167 | }; 168 | } 169 | Key::F(1) => { 170 | *loc = Location::Session; 171 | } 172 | Key::F(2) => { 173 | *loc = Location::Directory; 174 | } 175 | Key::F(3) => { 176 | *loc = Location::Machine; 177 | } 178 | Key::F(4) => { 179 | *loc = Location::Everywhere; 180 | } 181 | Key::F(5) => { 182 | *grouped = !*grouped; 183 | } 184 | Key::F(6) => { 185 | if get_focus_session().is_none() { 186 | focus_session( 187 | &((*sel.selected_items[0]).as_any().downcast_ref::()) 188 | .unwrap() 189 | .session(), 190 | ); 191 | } else { 192 | reset_focus_session(); 193 | } 194 | } 195 | Key::F(7) => { 196 | if get_focus_dir().is_none() { 197 | focus_dir( 198 | &((*sel.selected_items[0]).as_any().downcast_ref::()) 199 | .unwrap() 200 | .dir(), 201 | ); 202 | } else { 203 | reset_focus_dir(); 204 | } 205 | } 206 | Key::Ctrl('r') => { 207 | *loc = match *loc { 208 | Location::Session => Location::Directory, 209 | Location::Directory => Location::Machine, 210 | Location::Machine => Location::Everywhere, 211 | Location::Everywhere => Location::Session, 212 | }; 213 | } 214 | _ => (), 215 | }; 216 | return SelectionResult { 217 | selected_cmd: None, 218 | abort: false, 219 | }; 220 | } else { 221 | return SelectionResult { 222 | selected_cmd: None, 223 | abort: true, 224 | }; 225 | } 226 | } 227 | 228 | fn main() -> Result<()> { 229 | let _conn = 230 | Connection::open_with_flags(get_histdb_database(), OpenFlags::SQLITE_OPEN_READ_ONLY); 231 | 232 | let args: Vec = env::args().collect(); 233 | let query = |args: Vec| -> String { 234 | if args.len() > 1 { 235 | return args[1].to_string(); 236 | } 237 | return "".to_string(); 238 | }(args); 239 | 240 | if query == "--version" { 241 | println!("v0.9.6"); 242 | std::process::exit(1); 243 | } 244 | 245 | let result = show_history(query); 246 | if result.is_ok() { 247 | println!("{}", result.ok().unwrap()); 248 | } else { 249 | eprintln!("{}", result.err().unwrap()); 250 | std::process::exit(1); 251 | } 252 | 253 | Ok(()) 254 | } 255 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "once_cell", 13 | "version_check", 14 | "zerocopy", 15 | ] 16 | 17 | [[package]] 18 | name = "aho-corasick" 19 | version = "1.1.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 22 | dependencies = [ 23 | "memchr", 24 | ] 25 | 26 | [[package]] 27 | name = "allocator-api2" 28 | version = "0.2.18" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 31 | 32 | [[package]] 33 | name = "android-tzdata" 34 | version = "0.1.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 37 | 38 | [[package]] 39 | name = "android_system_properties" 40 | version = "0.1.5" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 43 | dependencies = [ 44 | "libc", 45 | ] 46 | 47 | [[package]] 48 | name = "arrayvec" 49 | version = "0.7.4" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 52 | 53 | [[package]] 54 | name = "autocfg" 55 | version = "1.3.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 58 | 59 | [[package]] 60 | name = "beef" 61 | version = "0.5.2" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" 64 | 65 | [[package]] 66 | name = "bitflags" 67 | version = "1.3.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 70 | 71 | [[package]] 72 | name = "bitflags" 73 | version = "2.6.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 76 | 77 | [[package]] 78 | name = "bumpalo" 79 | version = "3.16.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 82 | 83 | [[package]] 84 | name = "cc" 85 | version = "1.1.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" 88 | 89 | [[package]] 90 | name = "cfg-if" 91 | version = "1.0.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 94 | 95 | [[package]] 96 | name = "chrono" 97 | version = "0.4.38" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 100 | dependencies = [ 101 | "android-tzdata", 102 | "iana-time-zone", 103 | "js-sys", 104 | "num-traits", 105 | "wasm-bindgen", 106 | "windows-targets", 107 | ] 108 | 109 | [[package]] 110 | name = "core-foundation-sys" 111 | version = "0.8.6" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 114 | 115 | [[package]] 116 | name = "crossbeam" 117 | version = "0.8.4" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" 120 | dependencies = [ 121 | "crossbeam-channel", 122 | "crossbeam-deque", 123 | "crossbeam-epoch", 124 | "crossbeam-queue", 125 | "crossbeam-utils", 126 | ] 127 | 128 | [[package]] 129 | name = "crossbeam-channel" 130 | version = "0.5.13" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" 133 | dependencies = [ 134 | "crossbeam-utils", 135 | ] 136 | 137 | [[package]] 138 | name = "crossbeam-deque" 139 | version = "0.8.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 142 | dependencies = [ 143 | "crossbeam-epoch", 144 | "crossbeam-utils", 145 | ] 146 | 147 | [[package]] 148 | name = "crossbeam-epoch" 149 | version = "0.9.18" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 152 | dependencies = [ 153 | "crossbeam-utils", 154 | ] 155 | 156 | [[package]] 157 | name = "crossbeam-queue" 158 | version = "0.3.11" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 161 | dependencies = [ 162 | "crossbeam-utils", 163 | ] 164 | 165 | [[package]] 166 | name = "crossbeam-utils" 167 | version = "0.8.20" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 170 | 171 | [[package]] 172 | name = "darling" 173 | version = "0.14.4" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" 176 | dependencies = [ 177 | "darling_core", 178 | "darling_macro", 179 | ] 180 | 181 | [[package]] 182 | name = "darling_core" 183 | version = "0.14.4" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" 186 | dependencies = [ 187 | "fnv", 188 | "ident_case", 189 | "proc-macro2", 190 | "quote", 191 | "strsim", 192 | "syn 1.0.109", 193 | ] 194 | 195 | [[package]] 196 | name = "darling_macro" 197 | version = "0.14.4" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" 200 | dependencies = [ 201 | "darling_core", 202 | "quote", 203 | "syn 1.0.109", 204 | ] 205 | 206 | [[package]] 207 | name = "defer-drop" 208 | version = "1.3.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "f613ec9fa66a6b28cdb1842b27f9adf24f39f9afc4dcdd9fdecee4aca7945c57" 211 | dependencies = [ 212 | "crossbeam-channel", 213 | "once_cell", 214 | ] 215 | 216 | [[package]] 217 | name = "deranged" 218 | version = "0.3.11" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 221 | dependencies = [ 222 | "powerfmt", 223 | ] 224 | 225 | [[package]] 226 | name = "derive_builder" 227 | version = "0.11.2" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" 230 | dependencies = [ 231 | "derive_builder_macro", 232 | ] 233 | 234 | [[package]] 235 | name = "derive_builder_core" 236 | version = "0.11.2" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" 239 | dependencies = [ 240 | "darling", 241 | "proc-macro2", 242 | "quote", 243 | "syn 1.0.109", 244 | ] 245 | 246 | [[package]] 247 | name = "derive_builder_macro" 248 | version = "0.11.2" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" 251 | dependencies = [ 252 | "derive_builder_core", 253 | "syn 1.0.109", 254 | ] 255 | 256 | [[package]] 257 | name = "dirs-next" 258 | version = "2.0.0" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 261 | dependencies = [ 262 | "cfg-if", 263 | "dirs-sys-next", 264 | ] 265 | 266 | [[package]] 267 | name = "dirs-sys-next" 268 | version = "0.1.2" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 271 | dependencies = [ 272 | "libc", 273 | "redox_users", 274 | "winapi", 275 | ] 276 | 277 | [[package]] 278 | name = "either" 279 | version = "1.13.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 282 | 283 | [[package]] 284 | name = "enum-map" 285 | version = "2.7.3" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" 288 | dependencies = [ 289 | "enum-map-derive", 290 | ] 291 | 292 | [[package]] 293 | name = "enum-map-derive" 294 | version = "0.17.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" 297 | dependencies = [ 298 | "proc-macro2", 299 | "quote", 300 | "syn 2.0.70", 301 | ] 302 | 303 | [[package]] 304 | name = "fallible-iterator" 305 | version = "0.2.0" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 308 | 309 | [[package]] 310 | name = "fallible-streaming-iterator" 311 | version = "0.1.9" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" 314 | 315 | [[package]] 316 | name = "fnv" 317 | version = "1.0.7" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 320 | 321 | [[package]] 322 | name = "fuzzy-matcher" 323 | version = "0.3.7" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" 326 | dependencies = [ 327 | "thread_local", 328 | ] 329 | 330 | [[package]] 331 | name = "getrandom" 332 | version = "0.2.15" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 335 | dependencies = [ 336 | "cfg-if", 337 | "libc", 338 | "wasi", 339 | ] 340 | 341 | [[package]] 342 | name = "hashbrown" 343 | version = "0.14.5" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 346 | dependencies = [ 347 | "ahash", 348 | "allocator-api2", 349 | ] 350 | 351 | [[package]] 352 | name = "hashlink" 353 | version = "0.8.4" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" 356 | dependencies = [ 357 | "hashbrown", 358 | ] 359 | 360 | [[package]] 361 | name = "humantime" 362 | version = "2.1.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 365 | 366 | [[package]] 367 | name = "iana-time-zone" 368 | version = "0.1.60" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 371 | dependencies = [ 372 | "android_system_properties", 373 | "core-foundation-sys", 374 | "iana-time-zone-haiku", 375 | "js-sys", 376 | "wasm-bindgen", 377 | "windows-core", 378 | ] 379 | 380 | [[package]] 381 | name = "iana-time-zone-haiku" 382 | version = "0.1.2" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 385 | dependencies = [ 386 | "cc", 387 | ] 388 | 389 | [[package]] 390 | name = "ident_case" 391 | version = "1.0.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 394 | 395 | [[package]] 396 | name = "js-sys" 397 | version = "0.3.69" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 400 | dependencies = [ 401 | "wasm-bindgen", 402 | ] 403 | 404 | [[package]] 405 | name = "lazy_static" 406 | version = "1.5.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 409 | 410 | [[package]] 411 | name = "libc" 412 | version = "0.2.155" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 415 | 416 | [[package]] 417 | name = "libredox" 418 | version = "0.1.3" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 421 | dependencies = [ 422 | "bitflags 2.6.0", 423 | "libc", 424 | ] 425 | 426 | [[package]] 427 | name = "libsqlite3-sys" 428 | version = "0.25.2" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" 431 | dependencies = [ 432 | "pkg-config", 433 | "vcpkg", 434 | ] 435 | 436 | [[package]] 437 | name = "log" 438 | version = "0.4.22" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 441 | 442 | [[package]] 443 | name = "memchr" 444 | version = "2.7.4" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 447 | 448 | [[package]] 449 | name = "memoffset" 450 | version = "0.6.5" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 453 | dependencies = [ 454 | "autocfg", 455 | ] 456 | 457 | [[package]] 458 | name = "nix" 459 | version = "0.24.3" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" 462 | dependencies = [ 463 | "bitflags 1.3.2", 464 | "cfg-if", 465 | "libc", 466 | ] 467 | 468 | [[package]] 469 | name = "nix" 470 | version = "0.25.1" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" 473 | dependencies = [ 474 | "autocfg", 475 | "bitflags 1.3.2", 476 | "cfg-if", 477 | "libc", 478 | "memoffset", 479 | "pin-utils", 480 | ] 481 | 482 | [[package]] 483 | name = "num-conv" 484 | version = "0.1.0" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 487 | 488 | [[package]] 489 | name = "num-traits" 490 | version = "0.2.19" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 493 | dependencies = [ 494 | "autocfg", 495 | ] 496 | 497 | [[package]] 498 | name = "once_cell" 499 | version = "1.19.0" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 502 | 503 | [[package]] 504 | name = "pin-utils" 505 | version = "0.1.0" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 508 | 509 | [[package]] 510 | name = "pkg-config" 511 | version = "0.3.30" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 514 | 515 | [[package]] 516 | name = "powerfmt" 517 | version = "0.2.0" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 520 | 521 | [[package]] 522 | name = "proc-macro2" 523 | version = "1.0.86" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 526 | dependencies = [ 527 | "unicode-ident", 528 | ] 529 | 530 | [[package]] 531 | name = "quote" 532 | version = "1.0.36" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 535 | dependencies = [ 536 | "proc-macro2", 537 | ] 538 | 539 | [[package]] 540 | name = "rayon" 541 | version = "1.10.0" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 544 | dependencies = [ 545 | "either", 546 | "rayon-core", 547 | ] 548 | 549 | [[package]] 550 | name = "rayon-core" 551 | version = "1.12.1" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 554 | dependencies = [ 555 | "crossbeam-deque", 556 | "crossbeam-utils", 557 | ] 558 | 559 | [[package]] 560 | name = "redox_users" 561 | version = "0.4.5" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" 564 | dependencies = [ 565 | "getrandom", 566 | "libredox", 567 | "thiserror", 568 | ] 569 | 570 | [[package]] 571 | name = "regex" 572 | version = "1.10.5" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 575 | dependencies = [ 576 | "aho-corasick", 577 | "memchr", 578 | "regex-automata", 579 | "regex-syntax", 580 | ] 581 | 582 | [[package]] 583 | name = "regex-automata" 584 | version = "0.4.7" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 587 | dependencies = [ 588 | "aho-corasick", 589 | "memchr", 590 | "regex-syntax", 591 | ] 592 | 593 | [[package]] 594 | name = "regex-syntax" 595 | version = "0.8.4" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 598 | 599 | [[package]] 600 | name = "rusqlite" 601 | version = "0.28.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" 604 | dependencies = [ 605 | "bitflags 1.3.2", 606 | "fallible-iterator", 607 | "fallible-streaming-iterator", 608 | "hashlink", 609 | "libsqlite3-sys", 610 | "smallvec", 611 | ] 612 | 613 | [[package]] 614 | name = "rustversion" 615 | version = "1.0.17" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 618 | 619 | [[package]] 620 | name = "serde" 621 | version = "1.0.204" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 624 | dependencies = [ 625 | "serde_derive", 626 | ] 627 | 628 | [[package]] 629 | name = "serde_derive" 630 | version = "1.0.204" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 633 | dependencies = [ 634 | "proc-macro2", 635 | "quote", 636 | "syn 2.0.70", 637 | ] 638 | 639 | [[package]] 640 | name = "skim" 641 | version = "0.10.4" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "e5d28de0a6cb2cdd83a076f1de9d965b973ae08b244df1aa70b432946dda0f32" 644 | dependencies = [ 645 | "beef", 646 | "bitflags 1.3.2", 647 | "chrono", 648 | "crossbeam", 649 | "defer-drop", 650 | "derive_builder", 651 | "fuzzy-matcher", 652 | "lazy_static", 653 | "log", 654 | "nix 0.25.1", 655 | "rayon", 656 | "regex", 657 | "time", 658 | "timer", 659 | "tuikit", 660 | "unicode-width", 661 | "vte", 662 | ] 663 | 664 | [[package]] 665 | name = "smallvec" 666 | version = "1.13.2" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 669 | 670 | [[package]] 671 | name = "smawk" 672 | version = "0.3.2" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 675 | 676 | [[package]] 677 | name = "strsim" 678 | version = "0.10.0" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 681 | 682 | [[package]] 683 | name = "syn" 684 | version = "1.0.109" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 687 | dependencies = [ 688 | "proc-macro2", 689 | "quote", 690 | "unicode-ident", 691 | ] 692 | 693 | [[package]] 694 | name = "syn" 695 | version = "2.0.70" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" 698 | dependencies = [ 699 | "proc-macro2", 700 | "quote", 701 | "unicode-ident", 702 | ] 703 | 704 | [[package]] 705 | name = "term" 706 | version = "0.7.0" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" 709 | dependencies = [ 710 | "dirs-next", 711 | "rustversion", 712 | "winapi", 713 | ] 714 | 715 | [[package]] 716 | name = "textwrap" 717 | version = "0.15.2" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" 720 | dependencies = [ 721 | "smawk", 722 | "unicode-linebreak", 723 | "unicode-width", 724 | ] 725 | 726 | [[package]] 727 | name = "thiserror" 728 | version = "1.0.61" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" 731 | dependencies = [ 732 | "thiserror-impl", 733 | ] 734 | 735 | [[package]] 736 | name = "thiserror-impl" 737 | version = "1.0.61" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" 740 | dependencies = [ 741 | "proc-macro2", 742 | "quote", 743 | "syn 2.0.70", 744 | ] 745 | 746 | [[package]] 747 | name = "thread_local" 748 | version = "1.1.8" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 751 | dependencies = [ 752 | "cfg-if", 753 | "once_cell", 754 | ] 755 | 756 | [[package]] 757 | name = "time" 758 | version = "0.3.36" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 761 | dependencies = [ 762 | "deranged", 763 | "num-conv", 764 | "powerfmt", 765 | "serde", 766 | "time-core", 767 | ] 768 | 769 | [[package]] 770 | name = "time-core" 771 | version = "0.1.2" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 774 | 775 | [[package]] 776 | name = "timer" 777 | version = "0.2.0" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" 780 | dependencies = [ 781 | "chrono", 782 | ] 783 | 784 | [[package]] 785 | name = "tuikit" 786 | version = "0.5.0" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "5e19c6ab038babee3d50c8c12ff8b910bdb2196f62278776422f50390d8e53d8" 789 | dependencies = [ 790 | "bitflags 1.3.2", 791 | "lazy_static", 792 | "log", 793 | "nix 0.24.3", 794 | "term", 795 | "unicode-width", 796 | ] 797 | 798 | [[package]] 799 | name = "unicode-ident" 800 | version = "1.0.12" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 803 | 804 | [[package]] 805 | name = "unicode-linebreak" 806 | version = "0.1.5" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 809 | 810 | [[package]] 811 | name = "unicode-width" 812 | version = "0.1.13" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 815 | 816 | [[package]] 817 | name = "utf8parse" 818 | version = "0.2.2" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 821 | 822 | [[package]] 823 | name = "vcpkg" 824 | version = "0.2.15" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 827 | 828 | [[package]] 829 | name = "version_check" 830 | version = "0.9.4" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 833 | 834 | [[package]] 835 | name = "vte" 836 | version = "0.11.1" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" 839 | dependencies = [ 840 | "arrayvec", 841 | "utf8parse", 842 | "vte_generate_state_changes", 843 | ] 844 | 845 | [[package]] 846 | name = "vte_generate_state_changes" 847 | version = "0.1.2" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" 850 | dependencies = [ 851 | "proc-macro2", 852 | "quote", 853 | ] 854 | 855 | [[package]] 856 | name = "wasi" 857 | version = "0.11.0+wasi-snapshot-preview1" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 860 | 861 | [[package]] 862 | name = "wasm-bindgen" 863 | version = "0.2.92" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 866 | dependencies = [ 867 | "cfg-if", 868 | "wasm-bindgen-macro", 869 | ] 870 | 871 | [[package]] 872 | name = "wasm-bindgen-backend" 873 | version = "0.2.92" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 876 | dependencies = [ 877 | "bumpalo", 878 | "log", 879 | "once_cell", 880 | "proc-macro2", 881 | "quote", 882 | "syn 2.0.70", 883 | "wasm-bindgen-shared", 884 | ] 885 | 886 | [[package]] 887 | name = "wasm-bindgen-macro" 888 | version = "0.2.92" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 891 | dependencies = [ 892 | "quote", 893 | "wasm-bindgen-macro-support", 894 | ] 895 | 896 | [[package]] 897 | name = "wasm-bindgen-macro-support" 898 | version = "0.2.92" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 901 | dependencies = [ 902 | "proc-macro2", 903 | "quote", 904 | "syn 2.0.70", 905 | "wasm-bindgen-backend", 906 | "wasm-bindgen-shared", 907 | ] 908 | 909 | [[package]] 910 | name = "wasm-bindgen-shared" 911 | version = "0.2.92" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 914 | 915 | [[package]] 916 | name = "winapi" 917 | version = "0.3.9" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 920 | dependencies = [ 921 | "winapi-i686-pc-windows-gnu", 922 | "winapi-x86_64-pc-windows-gnu", 923 | ] 924 | 925 | [[package]] 926 | name = "winapi-i686-pc-windows-gnu" 927 | version = "0.4.0" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 930 | 931 | [[package]] 932 | name = "winapi-x86_64-pc-windows-gnu" 933 | version = "0.4.0" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 936 | 937 | [[package]] 938 | name = "windows-core" 939 | version = "0.52.0" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 942 | dependencies = [ 943 | "windows-targets", 944 | ] 945 | 946 | [[package]] 947 | name = "windows-targets" 948 | version = "0.52.6" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 951 | dependencies = [ 952 | "windows_aarch64_gnullvm", 953 | "windows_aarch64_msvc", 954 | "windows_i686_gnu", 955 | "windows_i686_gnullvm", 956 | "windows_i686_msvc", 957 | "windows_x86_64_gnu", 958 | "windows_x86_64_gnullvm", 959 | "windows_x86_64_msvc", 960 | ] 961 | 962 | [[package]] 963 | name = "windows_aarch64_gnullvm" 964 | version = "0.52.6" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 967 | 968 | [[package]] 969 | name = "windows_aarch64_msvc" 970 | version = "0.52.6" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 973 | 974 | [[package]] 975 | name = "windows_i686_gnu" 976 | version = "0.52.6" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 979 | 980 | [[package]] 981 | name = "windows_i686_gnullvm" 982 | version = "0.52.6" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 985 | 986 | [[package]] 987 | name = "windows_i686_msvc" 988 | version = "0.52.6" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 991 | 992 | [[package]] 993 | name = "windows_x86_64_gnu" 994 | version = "0.52.6" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 997 | 998 | [[package]] 999 | name = "windows_x86_64_gnullvm" 1000 | version = "0.52.6" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1003 | 1004 | [[package]] 1005 | name = "windows_x86_64_msvc" 1006 | version = "0.52.6" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1009 | 1010 | [[package]] 1011 | name = "zerocopy" 1012 | version = "0.7.35" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1015 | dependencies = [ 1016 | "zerocopy-derive", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "zerocopy-derive" 1021 | version = "0.7.35" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1024 | dependencies = [ 1025 | "proc-macro2", 1026 | "quote", 1027 | "syn 2.0.70", 1028 | ] 1029 | 1030 | [[package]] 1031 | name = "zsh-histdb-skim" 1032 | version = "0.9.6" 1033 | dependencies = [ 1034 | "chrono", 1035 | "enum-map", 1036 | "humantime", 1037 | "log", 1038 | "once_cell", 1039 | "regex", 1040 | "rusqlite", 1041 | "skim", 1042 | "textwrap", 1043 | "tuikit", 1044 | ] 1045 | --------------------------------------------------------------------------------