diff --git a/README.md b/README.md index 4b3c4a7..2094310 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,15 @@ - **Most used zsh shortcuts**: `md`, `rd`, `mkcd`, `take`, `~` and `..` work exactly like zsh, while you can use `cd ...`, `cd ....` and `cd .....` for the other upwards navigation commands. - **`all`**: selects all files and subdirectories at its location as targets for `rd`, `rm`, `cp` and `mv`. - **Better autocompletion** with *Tab* key cycling through all options instead of just displaying them. +- **FZF shell bindings:** if *fzf* is installed, `sloth-bash` enables the standard Bash integration, including fuzzy history search on `Ctrl+R`. +- **Basic command colors:** enables colored output for `ls`, `dir`, `vdir` and `grep`, plus familiar aliases like `ll`, `la` and `l`. - **Case-insensitive command parsing:**, `ls`, `Ls`, `lS` or `LS`, your command will always work. - **Distrobox passthrough:** enter your distrobox shell with `distroboxname` and pass commands to your distroboxes running `distroboxname command` (and any additional arguments if needed after). As distroboxes follow the user's *`~/.bashrc`* file, sloth-bash also works from within them! ## Recommended usage - Install *[Starship](https://starship.rs)* for the complete experience. +- Install *[fzf](https://github.com/junegunn/fzf)* if you want the full fuzzy shell bindings. - Copy **sloth-bash** to **`~/.sloth-bash`** - Copy **alias-list** to **`~/.alias-list`** - Copy **starship.toml** to **`~/.config/starship.toml`** (not required if you don't wanna use *Starship*) -- Add **`source ~/.sloth-bash`** to the end of your `~/.bashrc` file \ No newline at end of file +- Add **`source ~/.sloth-bash`** to the end of your `~/.bashrc` file diff --git a/sloth-bash b/sloth-bash index bf42e41..88b6f94 100644 --- a/sloth-bash +++ b/sloth-bash @@ -1,4 +1,5 @@ -source ~/.alias-list +[[ -f ~/.alias-list ]] && source ~/.alias-list + # bash file manager shopt -s autocd function cd { @@ -43,6 +44,15 @@ detach() { fi nohup $resolved "${@:2}" > /dev/null 2>&1 & } + +_sloth_run_quick_lookup() { + if command -v timeout >/dev/null 2>&1; then + timeout 0.5s "$@" 2>/dev/null + else + "$@" 2>/dev/null + fi +} + # python3 wrapper and flatpak matcher command_not_found_handle() { local cmd_lower="${1,,}" @@ -74,26 +84,35 @@ command_not_found_handle() { fi shift local args=("$@") - if [[ -n "${FLATPAK_ALIASES[$cmd]}" ]]; then + if command -v flatpak >/dev/null 2>&1 && [[ -n "${FLATPAK_ALIASES[$cmd]}" ]]; then if flatpak info "${FLATPAK_ALIASES[$cmd]}" > /dev/null 2>&1; then flatpak run "${FLATPAK_ALIASES[$cmd]}" "${args[@]}" return $? fi fi - if [[ "${cmd,,}" != "kde" && "${cmd,,}" != "gnome" ]]; then + if command -v flatpak >/dev/null 2>&1 && [[ "${cmd,,}" != "kde" && "${cmd,,}" != "gnome" ]]; then local match - match=$(flatpak list --app --columns=application 2>/dev/null \ + match=$(_sloth_run_quick_lookup flatpak list --app --columns=application \ + | grep -v -i "Platform" \ + | grep -iF -m 1 "$cmd") + if [[ -n "$match" ]]; then + match=$(printf '%s\n' "$match" | head -n 1) + fi + if [[ -z "$match" ]]; then + match=$(_sloth_run_quick_lookup flatpak list --app --columns=application \ | grep -v -i "Platform" \ | grep -iE "(^|\.)${cmd}(\.|$)" \ | head -n 1) + fi if [[ -n "$match" ]]; then flatpak run "$match" "${args[@]}" return $? fi fi if command -v distrobox &>/dev/null; then - local distroBoxes=$(distrobox list 2>/dev/null | awk 'NR>1 {print $3}') - if echo "$distroBoxes" | grep -q "^${cmd}$"; then + local distroBoxes + distroBoxes=$(_sloth_run_quick_lookup distrobox list | awk 'NR>1 {print $3}') + if printf '%s\n' "$distroBoxes" | grep -Fxq "$cmd"; then if [[ -n "${args[0]}" ]]; then distrobox enter "$cmd" -- "${args[@]}" else @@ -161,6 +180,66 @@ _run_with_all() { command "$cmd" "${expanded[@]}" fi } + +_sloth_has_option_arg() { + local arg + for arg in "$@"; do + if [[ "$arg" == -- ]]; then + return 1 + fi + if [[ "$arg" == -* ]]; then + return 0 + fi + done + return 1 +} + +_sloth_total_size_bytes() { + local total + total=$(du -sb "$@" 2>/dev/null | awk 'END {print $1}') + if [[ "$total" =~ ^[0-9]+$ ]]; then + printf '%s\n' "$total" + return 0 + fi + + total=$(du -sk "$@" 2>/dev/null | awk '{sum += $1} END {print sum * 1024}') + if [[ "$total" =~ ^[0-9]+$ ]]; then + printf '%s\n' "$total" + return 0 + fi + + return 1 +} + +_sloth_fzf_history_search() { + command -v fzf >/dev/null 2>&1 || return 1 + + local selected + selected=$(fc -lnr 1 | awk 'NF && !seen[$0]++' | fzf --height 40% --layout=reverse --border --prompt='history> ' --query "$READLINE_LINE") || return 0 + + READLINE_LINE="$selected" + READLINE_POINT=${#READLINE_LINE} +} + +_sloth_enable_basic_colors() { + if command -v dircolors >/dev/null 2>&1; then + if [[ -r ~/.dircolors ]]; then + eval "$(dircolors -b ~/.dircolors)" + else + eval "$(dircolors -b)" + fi + alias ls='ls --color=auto' + alias dir='dir --color=auto' + alias vdir='vdir --color=auto' + alias grep='grep --color=auto' + LS_COLORS+=':ow=01;33' + fi + + alias ll='ls -l' + alias la='ls -A' + alias l='ls -CF' +} + # cp and mv replacers cp() { for a in "$@"; do @@ -172,13 +251,21 @@ cp() { command cp "$@" return $? fi + if _sloth_has_option_arg "$@"; then + command cp "$@" + return $? + fi local sources=("${@:1:$#-1}") - local total_size=$(du -cb "${sources[@]}" 2>/dev/null | tail -n 1 | awk '{print $1}') + local total_size + total_size=$(_sloth_total_size_bytes "${sources[@]}") || { + command cp "$@" + return $? + } local threshold=$((100 * 1024 * 1024)) - if [ "$total_size" -gt "$threshold" ]; then - command rsync -ah --info=progress2 "$@" + if (( total_size > threshold )); then + command rsync -ah --no-owner --no-group --info=progress2 "$@" else - command rsync -ah "$@" + command rsync -ah --no-owner --no-group "$@" fi } mv() { @@ -191,6 +278,10 @@ mv() { command mv "$@" return $? fi + if _sloth_has_option_arg "$@"; then + command mv "$@" + return $? + fi local dest="${@: -1}" local sources=("${@:1:$#-1}") local source_dir=$(dirname "${sources[0]}") @@ -199,12 +290,16 @@ mv() { command mv "$@" return $? fi - local total_size=$(du -cb "${sources[@]}" 2>/dev/null | tail -n 1 | awk '{print $1}') + local total_size + total_size=$(_sloth_total_size_bytes "${sources[@]}") || { + command mv "$@" + return $? + } local threshold=$((100 * 1024 * 1024)) - if [ "$total_size" -gt "$threshold" ]; then - command rsync -ah --info=progress2 --remove-source-files "$@" + if (( total_size > threshold )); then + command rsync -ah --no-owner --no-group --info=progress2 --remove-source-files "$@" else - command rsync -ah --remove-source-files "$@" + command rsync -ah --no-owner --no-group --remove-source-files "$@" fi } rm() { @@ -283,14 +378,21 @@ take() { mkcd "$arg" fi } -# rolling tab -bind 'set show-all-if-ambiguous on' -bind 'TAB:menu-complete' -# starship -if which starship &> /dev/null; then - eval "$(starship init bash)" -fi -# zellij -if which zellij &> /dev/null; then - eval "$(zellij setup --generate-auto-start bash)" +# interactive shell extras +if [[ $- == *i* ]]; then + _sloth_enable_basic_colors + # rolling tab + bind 'set show-all-if-ambiguous on' + bind 'TAB:menu-complete' + if command -v fzf >/dev/null 2>&1; then + eval "$(fzf --bash)" + fi + # starship + if command -v starship >/dev/null 2>&1; then + eval "$(starship init bash)" + fi + # zellij + if command -v zellij >/dev/null 2>&1; then + eval "$(zellij setup --generate-auto-start bash)" + fi fi diff --git a/starship.toml b/starship.toml index 9e58d98..cc5b62b 100644 --- a/starship.toml +++ b/starship.toml @@ -2,4 +2,4 @@ show_always = true [sudo] -disabled = false \ No newline at end of file +disabled = false