diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-05-19 11:15:10 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-05-19 11:15:10 +0900 |
| commit | b4b9266564d91a6d5b8bcbda0e3e3df5e60c108c (patch) | |
| tree | 345803f1853865049246bf59ac790c64d5269055 /linux/.local/bin | |
| parent | 043a5608aa442206b939cd5d4feff6454e431781 (diff) | |
updates
Diffstat (limited to 'linux/.local/bin')
| -rwxr-xr-x | linux/.local/bin/extract | 41 | ||||
| -rwxr-xr-x | linux/.local/bin/fzf | bin | 0 -> 4259992 bytes | |||
| -rwxr-xr-x | linux/.local/bin/fzffiles | 96 | ||||
| -rwxr-xr-x | linux/.local/bin/lastfiles | 83 | ||||
| -rwxr-xr-x | linux/.local/bin/lazysql | bin | 0 -> 16863416 bytes | |||
| -rwxr-xr-x | linux/.local/bin/openfiles | 34 | ||||
| -rwxr-xr-x | linux/.local/bin/rgafiles | 206 |
7 files changed, 460 insertions, 0 deletions
diff --git a/linux/.local/bin/extract b/linux/.local/bin/extract new file mode 100755 index 0000000..b352a70 --- /dev/null +++ b/linux/.local/bin/extract @@ -0,0 +1,41 @@ +#!/bin/sh + +# Default behavior: Extract archive into new directory +# Behavior with `-c` option: Extract contents into current directory + +while getopts "hc" o; do case "${o}" in + c) extracthere="True" ;; + *) printf 'Options:\n -c: Extract archive into current directory rather than a new one.\n' && exit ;; + esac done + +if [ -z "$extracthere" ]; then + archive="$(readlink -f "$*")" && + directory=${archive%.*} && + mkdir -p "$directory" && + cd "$directory" || exit +else + archive="$(readlink -f "$(echo "$*" | cut -d' ' -f2)")" +fi + +[ "$archive" = "" ] && printf 'Give archive to extract as argument.\n' && exit + +if [ -f "$archive" ]; then + case "$archive" in + *.tar.bz2 | *.tar.xz | *.tbz2) tar xvjf "$archive" ;; + *.tar.gz | *.tgz) tar xvzf "$archive" ;; + *.lzma) unlzma "$archive" ;; + *.bz2) bunzip2 "$archive" ;; + *.rar) unrar x -ad "$archive" ;; + *.gz) gunzip "$archive" ;; + *.tar) tar xvf "$archive" ;; + *.zip | *.jar | *.war) unzip "$archive" ;; + *.Z) uncompress "$archive" ;; + *.7z) 7z x "$archive" ;; + *.xz) unxz "$archive" ;; + *.exe) cabextract "$archive" ;; + *.ace) unace x "$archive" ;; + *) printf "extract: '%s' - unknown archive method\\n" "$archive" ;; + esac +else + printf 'File "%s" not found.\n' "$archive" +fi diff --git a/linux/.local/bin/fzf b/linux/.local/bin/fzf Binary files differnew file mode 100755 index 0000000..34e0152 --- /dev/null +++ b/linux/.local/bin/fzf diff --git a/linux/.local/bin/fzffiles b/linux/.local/bin/fzffiles new file mode 100755 index 0000000..58af9d0 --- /dev/null +++ b/linux/.local/bin/fzffiles @@ -0,0 +1,96 @@ +#!/bin/sh + +set -e + +# Set new line and tab for word splitting +IFS=' +' + +# Get the list of selected files with key bindings for specific paths +files=$(fzf \ + --header "^a pwd ^b public ^d .dotfiles ^f configs ^g git ^h home ^k desktop ^r scripts ^s suckless ^u staged files ^v private ^/ help" \ + --preview "selection={}; + clean=\$(printf '%s' \"\$selection\" | sed -e 's/^📄 //' -e 's/^✏ //' -e 's/^✅ //' -e 's/^❌ //' -e 's/^🔀 //' -e 's/^❓ //'); + [ -z \"\$clean\" ] && { echo 'No selection'; exit 0; } + target=\$(readlink -f \"\$clean\" 2>/dev/null || printf '%s' \"\$clean\"); + if [ -z \"\$target\" ]; then echo 'Could not resolve path'; exit 0; fi; + mime=\$(file --mime-type -b \"\$target\" 2>/dev/null); + case \"\$mime\" in + image/*) + echo \"[image preview disabled] \$target\"; + file -h \"\$target\"; + exit 0;; + esac; + if [ -f \"\$target\" ]; then + dir=\$(dirname \"\$target\"); + if git_root=\$(git -C \"\$dir\" rev-parse --show-toplevel 2>/dev/null); then + rel=\${target#\"\$git_root\"/}; + diff_output=\$(git -C \"\$git_root\" diff --color -- \"\$rel\"); + if [ -n \"\$diff_output\" ]; then printf '%s\n' \"\$diff_output\"; exit 0; fi; + diff_output=\$(git -C \"\$git_root\" diff --color --cached -- \"\$rel\"); + if [ -n \"\$diff_output\" ]; then printf '%s\n' \"\$diff_output\"; exit 0; fi; + fi; + fi; + if [ -d \"\$target\" ]; then + eza --color=always --long --all --header --icons --git \"\$target\"; + elif [ -f \"\$target\" ]; then + bat --color=always --style=header,grid --line-range=:500 \"\$target\"; + else + file -h \"\$target\"; + fi" \ + --reverse \ + --query="$1" \ + --multi \ + --exit-0 \ + --prompt " 💡 " \ + --bind "ctrl-a:change-prompt( ⚡ )+reload(fd -H -L -t f -E .Trash -E .git -E .cache -E node_modules -E .next -E dist -E build -E coverage -E target -E vendor -E .venv -E venv . $PWD)" \ + --bind "ctrl-b:change-prompt( 🌎 )+reload(fd -H -L -t f -E .Trash -E .git -E .cache -E node_modules -E .next -E dist -E build -E coverage -E target -E vendor -E .venv -E venv . ${XDG_PUBLICSHARE_DIR:-${HOME}/Public})" \ + --bind "ctrl-d:change-prompt( ⚙️ )+reload(fd -H -L -t f -E .Trash -E .git -E .cache -E node_modules -E .next -E dist -E build -E coverage -E target -E vendor -E .venv -E venv . ${XDG_DOTFILES_DIR:-${HOME}/.dotfiles})" \ + --bind "ctrl-f:change-prompt( 🗂️ )+reload(fd -H -L -t f -E .Trash -E .git -E .cache -E node_modules -E .next -E dist -E build -E coverage -E target -E vendor -E .venv -E venv . ${XDG_CONFIG_HOME:-${HOME}/.config})" \ + --bind "ctrl-g:change-prompt( )+reload(fd -H -L -t f -E .Trash -E .git -E .cache . $HOME/Private/repos $HOME/Public/repos)" \ + --bind "ctrl-h:change-prompt( 🏠 )+reload(fd -H -L -t f -E .Trash -E .git -E .cache . $HOME)" \ + --bind "ctrl-k:change-prompt( 🖥️ )+reload(fd -H -L -t f -E .Trash -E .git -E .cache . ${XDG_DESKTOP_DIR:-${HOME}/Desktop})" \ + --bind "ctrl-r:change-prompt( 👟 )+reload(fd -H -L -t f -E .Trash -E .git -E .cache -E zsh . ${XDG_SCRIPTS_HOME:-${HOME}/.local/bin})" \ + --bind "ctrl-s:change-prompt( 🛠 )+reload(find ${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless -maxdepth 2 -type f -not -path '*/.git/*')" \ + --bind "ctrl-u:change-prompt( 📝 )+reload(if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then top=\$(git rev-parse --show-toplevel 2>/dev/null); git -C \"\$top\" status --porcelain | awk -v root=\"\$top\" '{ + staged=substr(\$0,1,1); + unstaged=substr(\$0,2,1); + file=substr(\$0,4); + gsub(/^ +/, \"\", file); + if (file == \"\") next; + if (staged == \"?\" && unstaged == \"?\") icon=\"📄\"; + else if (staged == \"!\" && unstaged == \"!\") icon=\"❌\"; + else if (staged != \" \" && staged != \"?\" && unstaged != \" \" && unstaged != \"?\") icon=\"🔀\"; + else if (staged != \" \" && staged != \"?\") icon=\"✅\"; + else if (unstaged != \" \") icon=\"✏\"; + else icon=\"❓\"; + print icon \" \" root \"/\" file + }'; else echo 'This is not a git repository.'; fi)" \ + --bind "ctrl-v:change-prompt( 🔒 )+reload(fd -H -L -t f -E .Trash -E .git -E .cache . $HOME/Private)" \ + --bind 'ctrl-/:change-prompt( ❓ )+reload(echo "^a all +^b public +^c configs +^d .dotfiles +^g git +^k desktop +^r scripts +^s suckless +^u staged files +^v private +^/ help")') + +# Check if any files were selected, and exit if not +[ -z "$files" ] && exit 0 + +files=$(printf '%s\n' "$files" | sed -e 's/^📄 //' -e 's/^✏ //' -e 's/^✅ //' -e 's/^❌ //' -e 's/^🔀 //' -e 's/^❓ //') + +if [ -d "$files" ]; then + absolute_files=$(realpath $files) + if echo "$absolute_files" | while read -r file; do file --mime-type "$file" | grep -q 'video/'; done; then + mpv --quiet --loop $absolute_files + else + openfiles "$absolute_files" + fi +else + openfiles "$files" +fi diff --git a/linux/.local/bin/lastfiles b/linux/.local/bin/lastfiles new file mode 100755 index 0000000..ba8c11a --- /dev/null +++ b/linux/.local/bin/lastfiles @@ -0,0 +1,83 @@ +#!/bin/sh + +# Display help message +usage() { + echo "Open the most recent file or the list of old files in fzf edited by vim." + echo "" + echo "Usage: ${0##*/} [OPTION]" + echo "" + echo "Options:" + echo " : Open the most recent old file in Vim." + echo " -h, --help : Show this help message." + echo " -l, --list : Show all recent files in Vim using fzf." + echo "" + echo "Examples:" + echo " ${0##*/} # Open the most recent file." + echo " ${0##*/} -l # Show all recent files in fzf and select to open." + exit 0 +} + +# List and handle oldfiles +list_oldfiles() { + # Fetch the oldfiles list from Vim's viminfo (file-mark entries start with '> ') + viminfo="${VIMINFO:-${HOME}/.viminfo}" + if [ ! -f "$viminfo" ]; then + echo "No viminfo found at $viminfo" >&2 + exit 1 + fi + + oldfiles=$(awk '/^> / {sub(/^> /,""); print}' "$viminfo" | sed "s|^~|$HOME|") + + # Exit if no oldfiles are found + [ -z "$oldfiles" ] && { + echo "No recent files found in Vim." >&2 + exit 1 + } + + case "$1" in + -h | --help) + usage + ;; + -l | --list) + # Filter valid files + valid_files=$(echo "$oldfiles" | while IFS= read -r file; do + [ -f "$file" ] && printf "%s\n" "$file" + done) + + # Exit if no valid files exist + [ -z "$valid_files" ] && { + echo "No valid files found." >&2 + exit 1 + } + + # Use fzf to select files + selected_files=$(echo "$valid_files" | + fzf \ + --multi \ + --preview 'bat -n --color=always --line-range=:500 {} 2>/dev/null || echo "Error previewing file"' \ + --height=70% \ + --reverse) + + # Exit if no files were selected + [ -z "$selected_files" ] && exit 1 + + # Open selected files in Vim + openfiles "$selected_files" + ;; + *) + # Open the most recent file + for file in $oldfiles; do + if [ -f "$file" ]; then + openfiles "$file" + exit 0 + fi + done + + echo "No valid recent files found." >&2 + exit 1 + ;; + esac +} + +# Parse command-line arguments +list_oldfiles "$@" diff --git a/linux/.local/bin/lazysql b/linux/.local/bin/lazysql Binary files differnew file mode 100755 index 0000000..1fe6af4 --- /dev/null +++ b/linux/.local/bin/lazysql diff --git a/linux/.local/bin/openfiles b/linux/.local/bin/openfiles new file mode 100755 index 0000000..f35aef1 --- /dev/null +++ b/linux/.local/bin/openfiles @@ -0,0 +1,34 @@ +#!/bin/sh + +if ! command -v vim >/dev/null 2>&1; then + echo "Error: 'vim' is not installed." >&2 + exit 1 +fi + +IFS=' +' + +files=$* + +for file in $files; do + files_list="$files_list \"$(realpath "$file")\"" +done + +eval "set -- $files_list" + +count=$# + +case "$count" in +2) + ${EDITOR:-vim} -O +'silent! normal g;' "$@" -c 'wincmd t' + ;; +3) + ${EDITOR:-vim} -O "$1" -c 'wincmd j' -c "silent! vsplit $2" -c "silent! split $3" -c 'wincmd t' + ;; +4) + ${EDITOR:-vim} -O "$1" -c "silent! vsplit $2" -c "silent! split $3" -c 'wincmd h' -c "silent! split $4" -c 'wincmd t' + ;; +*) + ${EDITOR:-vim} "$@" + ;; +esac diff --git a/linux/.local/bin/rgafiles b/linux/.local/bin/rgafiles new file mode 100755 index 0000000..2fc8488 --- /dev/null +++ b/linux/.local/bin/rgafiles @@ -0,0 +1,206 @@ +#!/bin/sh + +# Usage function to display script options +usage() { + echo "Find files using ripgrep and open them in Vim." + echo "" + echo "Usage: ${0##*/} [-s] [-i] [-l] [-p] [<tag>] <query>" + echo "" + echo "Options:" + echo " -h : Show this message" + echo " -i : Perform a case-insensitive search (default)" + echo " -l : List files associated with the given tag" + echo " -p : Search for files in the specified project directories using the specified tag (default: PROJECT)" + echo " -s : Perform a case-sensitive search" + echo " [<tag>] <query> : Optional tag for project mode, followed by the search query" + echo "" + echo "Examples:" + echo " ${0##*/} -p TODO 'KEYWORD' # Search for 'KEYWORD' in files tagged with 'TODO' in the project directories" + echo " ${0##*/} -l -p 'KEYWORD' # List files associated with the default 'PROJECT' tag and 'KEYWORD'" + echo " ${0##*/} 'KEYWORD' # Open files containing 'KEYWORD' in vim" + exit 0 +} + +search_term() { + case_flag="$1" + shift + + if ! command -v rga >/dev/null 2>&1; then + echo "Error: 'rga' is not installed." >&2 + exit 1 + fi + if ! command -v xclip >/dev/null 2>&1; then + echo "Error: 'xclip' is not installed." >&2 + exit 1 + fi + + # Construct the preview command + preview_cmd=$(printf "rga %s --pretty --context 10 '%s' {}" "$case_flag" "$*") + query="$*" + rga_output=$(rga --follow --no-ignore --hidden --text --max-count=1 ${case_flag:+$case_flag} --files-with-matches --no-messages \ + --glob '!**/.cache/*' \ + --glob '!**/.git/*' \ + --glob '!**/.github/*' \ + --glob '!**/.next/*' \ + --glob '!**/.venv/*' \ + --glob '!**/build/*' \ + --glob '!**/coverage/*' \ + --glob '!**/dist/*' \ + --glob '!**/node_modules/*' \ + --glob '!**/target/*' \ + --glob '!**/vendor/*' \ + --glob '!**/venv/*' \ + "$query") + + # Use fzf to select files + files=$(echo "$rga_output" | fzf +m --preview="$preview_cmd" --reverse --multi --select-1 --exit-0) || return 1 + + # Check if files are selected + if [ -z "$files" ]; then + echo "No files selected." + return 0 + fi + + # copy target to the clipboard + echo "$query" | xclip -selection clipboard 2>/dev/null + + # Open files at matching lines + count=$(echo "$files" | wc -l) + if [ "$count" -eq 1 ]; then + # Find the first matching line number in the selected file + line=$(rga --max-count=1 --line-number --no-filename ${case_flag:+$case_flag} --no-messages "$query" "$files" 2>/dev/null | head -1 | cut -d: -f1) + if [ -n "$line" ]; then + ${EDITOR:-vim} "+${line}" "$(realpath "$files")" + else + openfiles "$files" + fi + else + # Multiple files: open at matching lines via quickfix + tmpfile=$(mktemp) + echo "$files" | while IFS= read -r file; do + match=$(rga --max-count=1 --line-number --no-filename ${case_flag:+$case_flag} --no-messages "$query" "$file" 2>/dev/null | head -1) + if [ -n "$match" ]; then + printf '%s:%s\n' "$(realpath "$file")" "$match" >> "$tmpfile" + else + printf '%s:1:\n' "$(realpath "$file")" >> "$tmpfile" + fi + done + if [ "$count" -lt 5 ]; then + ${EDITOR:-vim} -q "$tmpfile" \ + -c 'for i in range(2,len(getqflist())) | vsplit | execute "cc ".i | endfor | wincmd t' + else + first_line=$(head -1 "$tmpfile" | cut -d: -f2) + file_args="" + while IFS=: read -r fpath _; do + file_args="$file_args \"$fpath\"" + done < "$tmpfile" + eval "${EDITOR:-vim}" "+${first_line}" "$file_args" + fi + rm -f "$tmpfile" + fi + + # print the file names + echo "$rga_output" +} + +# Function to list and/or open all files associated with a given project tag +list_or_open_project_files() { + # Use the provided tag or default to "PROJECT" + project_tag="${1:-PROJECT}: $2" + + # Define the project paths as a space-separated string + project_paths="$HOME/.dotfiles $HOME/.local/src/suckless $HOME/Public/repos" + + # Use rga to find files containing the project tag across all project paths + rga_output="" + for path in $project_paths; do + if [ -d "$path" ]; then + rga_result=$(rga --follow --no-ignore --hidden --text --max-count=1 --files-with-matches --no-messages \ + --glob '!**/.cache/*' \ + --glob '!**/.git/*' \ + --glob '!**/.github/*' \ + --glob '!**/.next/*' \ + --glob '!**/.venv/*' \ + --glob '!**/build/*' \ + --glob '!**/coverage/*' \ + --glob '!**/dist/*' \ + --glob '!**/node_modules/*' \ + --glob '!**/target/*' \ + --glob '!**/vendor/*' \ + --glob '!**/venv/*' \ + "$project_tag" "$path") + rga_output="$rga_output $rga_result" + fi + done + + # Remove leading/trailing whitespace + rga_output=$(echo "$rga_output" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + + # Check if any files were found + if [ -z "$rga_output" ]; then + echo "No files found for tag $project_tag." + return 0 + fi + + # If the script was called in list mode, simply print the files + if [ "$list_mode" -eq 1 ]; then + echo "$rga_output" + else + # Open files at matching lines + file_count=$(echo "$rga_output" | wc -w) + if [ "$file_count" -eq 1 ]; then + line=$(rga --max-count=1 --line-number --no-filename --no-messages "$project_tag" "$rga_output" 2>/dev/null | head -1 | cut -d: -f1) + if [ -n "$line" ]; then + ${EDITOR:-vim} "+${line}" "$(realpath "$rga_output")" + else + openfiles "$rga_output" + fi + else + # Multiple files: open at matching lines via quickfix + tmpfile=$(mktemp) + for file in $rga_output; do + match=$(rga --max-count=1 --line-number --no-filename --no-messages "$project_tag" "$file" 2>/dev/null | head -1) + if [ -n "$match" ]; then + printf '%s:%s\n' "$(realpath "$file")" "$match" >> "$tmpfile" + else + printf '%s:1:\n' "$(realpath "$file")" >> "$tmpfile" + fi + done + if [ "$file_count" -lt 5 ]; then + ${EDITOR:-vim} -q "$tmpfile" \ + -c 'for i in range(2,len(getqflist())) | vsplit | execute "cc ".i | endfor | wincmd t' + else + ${EDITOR:-vim} -q "$tmpfile" \ + -c 'silent! for i in range(2,len(getqflist())+1) | execute "silent! cc ".i | endfor | silent! cfirst' + fi + rm -f "$tmpfile" + fi + fi +} + +# Main function to handle options +case_flag="--ignore-case" # Default to case-insensitive +list_mode=0 +project_mode=0 + +# Parse the options +while getopts "silph" opt; do + case $opt in + s) case_flag="--case-sensitive" ;; # Case-sensitive + i) case_flag="--ignore-case" ;; # Case-insensitive + l) list_mode=1 ;; # List mode + p) project_mode=1 ;; # Project mode + h) usage ;; + *) ;; + esac +done + +shift $((OPTIND - 1)) + +# Handle project mode search +if [ "$project_mode" -eq 1 ]; then + list_or_open_project_files "$1" "$2" +else + # Otherwise, call the common search function + search_term "$case_flag" "$@" +fi |
