Skip to content

Instantly share code, notes, and snippets.

@100ideas
Last active March 17, 2022 04:11
Show Gist options
  • Save 100ideas/b27e44a5c07360917ce99cd6997e2b7b to your computer and use it in GitHub Desktop.
Save 100ideas/b27e44a5c07360917ce99cd6997e2b7b to your computer and use it in GitHub Desktop.
lsfuncs.fish: Print user-defined Fish functions (including any executable files in first path of `$fish_user_paths`)
#!/usr/bin/env bash
#
#!/usr/bin/env bash
#: Usage: brew lsbrews [OPTION]
#:
#: list name: description of all instealled "leaf" formulae
#:
# disables logging the script's contents to .bash_history
set +o history
# redirect stderr to both console (stdout) and stderr
# https://unix.stackexchange.com/q/195169
# exec 3> >(tee -a log)
# exec 4>>log
# exec >&4 2>&3
echo "starting brew-lsbrews"
declare -i MISSING
declare -i STALE
# script seems to be using '/' for $XDG_CONFIG_HOME, so tries to write log to
# /bin/brew-lsbrews.cache
# disabling for now until chown later
# if [ ! -v $XDG_CONFIG_HOME ]; then XDG_CONFIG_HOME='/Users/100ideas/.config'; fi
# CACHE_FILE="$XDG_CONFIG_HOME/bin/brew-lsbrews.cache"
CACHE_FILE='/Users/100ideas/.config/bin/brew-lsbrews.cache'
if [ ! -f $CACHE_FILE ]; then
MISSING=1; echo "SETTING UP cache AT: ${CACHE_FILE}"
printf "\n\n WARN! brew-lsbrew (maybe via lsfuncs) is missing its brew-lsbrew.cache file and needs help creating it; do\n\n\t \$ touch $CACHE_FILE\n\n to fix. exiting...\n\n"
touch "$CACHE_FILE" # wont work w/o danger enable chmod chgrp to allow script access...
exit 1
elif [ $(wc -l $CACHE_FILE | cut -c 1-9) -lt 2 ]; then
echo "brew-lsbrews cache file exists but is empty... regenerating...";
MISSING=1;
else
MISSING=0;
fi
# echo "cache exists? ($?)"; if [ $MISSING ]; then echo "yep missing missing=$MISSING"; else echo "nope seems to be here=$MISSING"; fi
OLDLINES=$(wc -l $CACHE_FILE | cut -c 1-9)
# cache file older-than (-nt) brew bin dir?
if [[ ($MISSING -gt 0) || "$CACHE_FILE" -ot "$(brew --prefix)/bin" ]]; then STALE=1; else STALE=0; fi
# echo "cache stale? ($?)" $(if [ $STALE -gt 0 ]; then echo "yep!"; else echo "no..uhhh??"; fi)
if [ $STALE -gt 0 ]; then
printf "...lsbrews cache was stale, updating brew descriptions... last updates:\n"
printf "\t lsbrews: $(stat -f "%Sm" $CACHE_FILE)\n\t homebrew: $(stat -f "%Sm" /usr/local/bin/)\n"
# brew info --json --installed | jq --raw-output 'map(select(.installed[].installed_as_dependency == false) | [.name, .desc]) | .[] | @tsv' > "$CACHE_FILE" 2>/dev/null
brew info --json --installed | jq --raw-output 'map(select(.installed[].installed_as_dependency == false) | [.name, .desc]) | .[] | @tsv' > $CACHE_FILE &
wait
NEWLINES=$(wc -l $CACHE_FILE | cut -c 1-9)
printf "done updating $CACHE_FILE - added %d new entries ($OLDLINES->$NEWLINES)\n\n" $(($NEWLINES - $OLDLINES))
fi
exit 0
# to split cache file lines by "\t":
# awk -F"\t" '{printf ("%s --- %s \n\n", $1, $2)}' brew-lsbrews.cache
# lsfuncs.fish: prints a dynamic list of user-installed Fish functions (and lists a user's brews and scripts found in ~/.config/bin)
#
# author @100ideas - github.com/100ideas
# latest revision Dec 2, 2021
# License: MIT
#
# published: 16 mar 2022
# public repo: public gist: https://gist.github.com/100ideas/b27e44a5c07360917ce99cd6997e2b7b
# potential discussion: https://github.com/ttscoff/fish_files/issues/2
# original: (private dotfiles repo): https://github.com/100ideas/dotfiles/blob/master/fish/functions/lsfuncs.fis
#
# do YOU have a growing list of fish shell scripts, functions, and miscellaneous other polyglot executables in your home
# directory? Do you sometomes forget what you named one of your recent (or ancient) scripts?
#
# this is a fish function that tries to list as many of these as it can find in a nice text table to you terminal.
#
# 1) lists all user-defined functions in a tabular list in terminal.
# it displays descriptions if available.
#
# 2) similarly, iterates through local ~/.config/bin directory and lists info about executables it finds there.
# I keep this dir in version control and just toss utility scripts and programs into...
#
# 3) Lastly, it generates & caches a plaintext log of all homebrew leaf 'brews' that have been installed
# (they don't depend on other brews so are likely to be main packages). Also does a list of kegs. Takes a while
# to generate the list so the func waits a while (day/week) before remaking it
#
# all this info is printed to terminal in a nice table for you to grep
#
# USAGE
#
# lsfuncs - prints "$name - #description" for each fish, brew, and misc script/binary
# found around users'$HOME (brew list is cached). Presumably each result is on users $PATH.
#
# EXAMPLE
#
# ~/dev❯ lsfuncs | grep color 20:57:11
# fish_colors_monokai - set fish color variables like monokai
# lscolors - print list of fish colors
# tree - Display directories as trees (with optional color/HTML output)
#
#
# INSTALL
#
# - depends on brew 'coreutils' because macos catalina/big bash does not have 'timeout' command
# - adjust hardcoded search paths to your liking below
# - put lsuncs in fish's path (~/$XDG_CONFIG_HOME/fish/functions/lsfuncs.fish)
#
#
set my_local_bins ~/dev/bin/
# set my_local_bins fish_user_paths[1] # instead of using fish_user_paths, just hardocde other dirs
function lsfuncs --description "Print user-defined Fish functions (including any executable files in first path of \$fish_user_paths).
Opts:
-a: only print fish functions;
-p <paths>: pass additional path(s) in which to search for potential scripts, bins, commands."
# NOT CURRENTLY USED
# eventually would be handy to return info on single command glob if provided via fish_opt & argparse
# i.e. `apropos` mode
# http://fishshell.com/docs/current/commands.html#fish_opt
set -l options (fish_opt -s a -l all) (fish_opt -s p -l paths)
argparse $options -- $argv
if test -n "$_flag_a"
# use fish built-in 'functions' command to get list of *.fish user scripts stored in conventional places
for fishfunc in (functions -a)
# and then again to get description string set by '--description' flag in script source
# i.e. 'function lsfuncs --description '<THIS STRING>'
set funcdesc (functions --details -v $fishfunc | tail -n 1)
if string match --ignore-case -e $fishfunc $funcdesc
set_color yellow
printf '%-24s - %.80s\n' "$fishfunc" (set_color normal) $funcdesc
end
end
# logic for user-provided paths via '-p' param
else if test -n "$_flag_p"
# only append user-provided paths if they exist
for p in $argv
if test -e $p
set my_local_bins $my_local_bins $p
end
end
# else if
# TBD
else
printf "\n############\n $options\n $_flag_a \n $_flag_p \n my_local_bins:\n$my_local_bins\n#############"
############################################################################
# look for user-defined fish functions
set_color brblue
printf "\n$fish_function_path[1]:\n"
for fishfunc in (ls $fish_function_path[1]/*.fish | sed -E "s#.*fish\/functions\/(.*)\.fish#\1#")
set_color yellow
printf '%-24s - %.80s\n' "$fishfunc" (set_color normal; functions --details -v $fishfunc | tail -n 1)
end
############################################################################
# look my other shell scripts
#
# I keep general-purpose scripts & tools in ~/.config/bin (symlinked to ~/dev/bin;
# with all of ~/.config kept in version control). This path is always the first entry in my $fish_user_paths or bash $PATH
set_color brblue
set -g userfunc # needed global scope so other func can get at tit
for userpath in $my_local_bins
printf "\n$userpath\n"
# loop through all paths that are executable and are not directories
for userfunc in (find $userpath\/* -d 0 -perm +755 -not -type d)
# is it a script or is it a binary?
set is_text (file -Ib $userfunc | grep '^.*text\/')
set_color yellow
if test -n "$is_text" # it's a script
printf '%-24s - %.80s\n' (echo $userfunc | sed -E "s#.*bin\/(.*)#\1#") \
# print first comment line (assumes comments start with with '#')
(set_color normal; sed -E '/^#!/d; s/^\s*# (.*)$/\1/p; s/_*description[_ =]*//p; d' $userfunc | head -n 1)
set is_text false
else # it's binary
# does a man page exist for the command? (asking man to return path to man page else return status 127)
if command man -w (basename $userfunc) > /dev/null 2>&1
# get description by parsing man page DESCRIPTION first line
printf '%-24s - %.80s\n' (echo $userfunc | sed -E "s#.*bin\/(.*)#\1#") \
(set_color normal; command man (basename $userfunc) | col -bx | grep -A 1 DESCRIPTION | tail -n 1 | string trim --left)
else
tryToGetHelpString ## TODO THIS FUNC IS NOT GETTING CALLED (for 'lc' binary in dev/bin for instance)
end
end
end
end
############################################################################
# cache, parse and print homebrew descriptions (only installed LEAF formulas)
# see ~/.config/bin/brew-lsbrews
set_color brblue
# set stale
set -l homebrew_bin (brew --prefix)"/bin/"
set -l cache "$XDG_CONFIG_HOME/bin/brew-lsbrews.cache"
set -l lsbrew "$XDG_CONFIG_HOME/bin/brew-lsbrews"
set -l stale true
set -l lsbrews_age (stat -f "%m" $cache)
set -l homebrews_age (stat -f "%m" $homebrew_bin)
set -l last_update (stat -f "%Sm" $cache)
set -l OLDLINES (wc -l $cache | cut -c 1-9)
# has homebrew has been updated OR is the cache file empty? regeneratate....
# echo "$lsbrews_age -gt $homebrews_age: "
# if test $lsbrews_age -gt $homebrews_age
# echo lsbrews yes
# end
# echo "(wc -l $cache | cut -c 1-9): $OLDLINES"
# if test $OLDLINES -lt 2
# echo $OLDLINES yes
# end
if test $lsbrews_age -gt $homebrews_age -a $OLDLINES -gt 2
set stale false
printf '\n%-24s - %.80s\n' $homebrew_bin "lsbrew.cache last updated $last_update"
else
set stale true
printf '\n%-24s - %.80s\n\n' $homebrew_bin "lsbrew.cache last updated $last_update "(set_color -u -o brred)"[STALE]"(set_color brblue)
set_color normal; set_color brblack
brew-lsbrews &
wait
end
# https://fishshell.com/docs/current/cmds/read.html?highlight=read#example
cat $cache | while read -l name desc
set_color yellow
printf '%-24s - %.80s\n' $name (set_color normal && echo $desc)
end
end
end
function tryToGetHelpString
set valid_help_param false
set help_text "" # zero-length string, if set to something test -n below is true
# printf "\n\ntrying $userfunc --help\n\n"
if timeout 1 sh -c "$userfunc --help" > /dev/null 2>&1
set valid_help_param "--help"
else if timeout 1 sh -c "$userfunc -h" > /dev/null 2>&1
set valid_help_param "-h"
end
echo "#### valid_help_param: $valid_help_param ####"
if test -n $valid_help_param
set help_text (timeout 1 sh -c "$userfunc $valid_help_param" | awk 'length($0) > 30' | head -n 1 | string trim --left)
else
set basecmd = (basename $userfunc)
# set help_text (timeout 1 sh -c "$userfunc" 2>&1)
# set help_text (cat $help_text | awk 'length($0) > 30' | head -n 1 | string trim --left)
# printf '%-24s - %.80s\n' (echo "got exec_output: $exec_output")
if tldr $basecmd | grep -A 2 $basecmd | head -n 3 | tail -n 2 | grep $basecmd
set help_text (tldr $basecmd | grep -A 2 $basecmd | head -n 3 | tail -n 2)
else if test (__fish_apropos $basecmd | grep -E "^$basecmd\(.*")
set help_text (apropos $basecmd | grep -E "^$basecmd\(.*")
set help_text (string split --right --max 1 ' - ' $help_text | tail -n 1)
else
set help_text "??? unsure"
end
end
printf '%-24s - %.80s\n' (echo basename $userfunc | sed -E "s#.*bin\/(.*)#\1#") \
(set_color normal; printf '%-24s - %.80s\n' $help_text)
end
# # try to exec binary with '-h' help flag then return first line
# printf '%-24s - %.80s\n' (echo $userfunc | sed -E "s#.*bin\/(.*)#\1#") \
# (set_color normal; sh -c "$userfunc -h" | awk 'length($0) > 30' | head -n 1 | string trim --left)
# else if sh -c "$userfunc --help" > /dev/null 2>&1
# printf '%-24s - %.80s\n' (echo $userfunc | sed -E "s#.*bin\/(.*)#\1#") \
# (set_color normal; sh -c "$userfunc --help" | awk 'length($0) > 30' | head -n 1 | string trim --left)
# else
# printf '%-24s - %.80s\n' (echo $userfunc | sed -E "s#.*bin\/(.*)#\1#") \ (set_color normal; echo "????")
# end
# end
set -eg userfunc
~/dev ❯ lsfuncs 16:23:57
############
a/all p/paths
my_local_bins:
/Users/100ideas/dev/bin/
#############
/Users/100ideas/.config/fish/functions:
athenapdf - Simple, Docker-powered PDF conversions - just supply URL
beef - start BeEF in docker
br - n/a
brewinfo - print formula/cask name desc homepage when argv is in desc
c - Improved cat, pygmentized
cdipfs - cd to ../ipfs/$argv dev dir
cfp - copy fullpath to clipboard: cfp <file>
clutter - show/hide osx desktop icons
conda_paths - toggles anaconda paths in fish_user_paths
connections - list local processes listening to network; -n for node, -p for only pids,
csf - lolcatcowfortune
dangerChrome - n/a
desc - Print the description of a Fish function.
dl - alias dl cd ~/Downloads
dsf - diff-so-fancy file/a file/b (works outside of git repos)
ffmpeg_pip - usage: stream1 stream2. ffmpeg encodes stream2 into stream1 (1080p or bigg
findnamed - recursively finds all files/folders that contain ARGV in name under curren
finfo - dynamic apropos just for fish functions
fish_append_user_path - append paths to tail of fish_user_paths array, or do nothing if already co
fish_audit - profile fish prompt performance
fish_colors_monokai - set fish color variables like monokai
fish_delete_user_path - remove given paths from UNIVERSAL fish_user_paths if they exist
fish_prepend_user_path - push paths to front of fish_user_paths array, or do nothing if already con
fish_prompt - n/a
fish_update_user_path - inserts/removes given paths to fish_user_paths
fish_user_key_bindings - n/a
fishedit - open fish config & user bin in vscode
fuck - Correct your previous console command
fzf_complete - n/a
fzf_config - n/a
fzf_key_bindings - n/a
gcl - shortcut for git clone <repo>; cd repo
getopts - 3rd-party cli options parser for fish funcs github.com/jorgebucaran/fish-g
gh - Open the current repository in github
gif-it - ffmpeg script to create gif. usage: input.mkv outputname starttime duratio
grepkill - kill ps that grep match arg (check first w/ psgrep)
hosts - switches /etc/hosts between default and StevenBlack blocklist
jupyterlab-anon - docker run -it --rm jupyter/scipy-notebook jupyter lab (localhost:8888)
jupyterlab - docker start -ai jupyterlab (localhost:8888)
keybinds - open fish & iterm2 keybind web docs
kindlecover - convert png to kindle-optimized grayscale dither w/ imagemagick
ls-scripts - list executable files that don\'t include \'.\' at given path (max depth 3
lsbrews - list all installed homebrew packages w/ description
lscolors - print list of fish colors
lsfuncs - Print user-defined Fish functions (including any executable files in first
lsrecent - lsrecent [numresults] [paths to skip]: list most recently edited files ben
man - Colored man pages
panscrape - give url, pandoc scrapes, outputs markdown
paths - alias paths str2lines $PATH $fish_user_paths
portainer-upgrade - update portainer image to latest version
psgrep - return pid of all ps that match grep (not self)
sigs - checks check input path code signatures and certs with codesign and spctl
str2lines - split input into newlines: str2lines [\'delimiter\'] input
update_all - homebrew, fish, npm -g, (no yarn yet), and Apple system update
wget-filetype - wget all *.<ext> at <url>: use wget-filetype <ext>, <url>
wget-pdfs - wget all pdfs at <http://site.tld/path>
where - Print the resolved absolute file name (uses realpath)
xh - list downloaded files from osx quarantine
/Users/100ideas/dev/bin/
apropos - 2020-02-12: patched apropos b/c apple broke it, making fish completions sl
brew-lsbrews - was #!/usr/local/bin/bash
brew-lsbrews.cache -
browsh - browsh: The modern, text-based browser
brute_upnproxy.sh - dump the first 1,000 UPnP NAT entries from the device's exposed TCP daemon
chromium.sh - https://developer.chrome.com/extensions/proxy
code - Copyright (c) Microsoft Corporation. All rights reserved.
crx-downlaod - shell script to download google chrome crx extension file from webstore
delete-all-ds_store.command - delete-all-ds_store.command
emacsapp - /Applications/Emacs.app/Contents/MacOS/Emacs "$@"
firefox_dev - uses osx metadata db to find and exec firefox dev edition binary
git-summary - git-summary - summarize git repos at some path
git_latest_commits - list remote branches ordered by most recent commit
handy.txt -
lc - lc tool is a license compiler for Mono. It's used to convert a
lsgits - list git repos under current directory
lsnodes - list node projects under current directory (looks for package.json files)
#### valid_help_param: false ####
basename - -
node-add-ignore.sh - bash script for ignoring all files in node_modules for Spotlight
node-del-modules.sh - delete node_modules folder recursively from a specified path using command
pdf-parser - 'pdf-parser, use it to parse a PDF document'
pdf-strip.sh - try to clone pdf without metadata
pdfid - 'Tool to test a PDF file'
pdftk - docker run --rm -v `pwd`:`pwd` -w `pwd` jottr/alpine-pdftk "$@"
proxify - The -d flag enables some diagnostic output, which primarily reports inter
safari-print-bookmarks - prints bookmarks given name of safari bookmark folder
safari-readinglist - A script for exporting Safari Reading List items to Markdown and Pinboard
screenlapse - records timelapse of desktop. frames and movie saved in ~/Movies/screenlap
torctl - start|stop torsocks w/ launch services
yamete - https://github.com/jaymoulin/yamete
/usr/local/bin/ - lsbrew.cache last updated Feb 23 15:37:22 2022 [STALE]
starting brew-lsbrews
...lsbrews cache was stale, updating brew descriptions... last updates:
lsbrews: Feb 23 15:37:22 2022
homebrew: Mar 16 01:55:14 2022
done updating /Users/100ideas/.config/bin/brew-lsbrews.cache - added 4 new entries ( 36 -> 40 )
b3sum - BLAKE3 cryptographic hash function
bat - Clone of cat(1) with syntax highlighting and Git integration
brightness - Change macOS display brightness from the command-line
broot - New way to see and navigate directory trees
certbot - Tool to obtain certs from Let's Encrypt and autoenable HTTPS
ckan - Comprehensive Kerbal Archive Network
clojure - The Clojure Programming Language
coreutils - GNU File, Shell, and Text utilities
cowsay - Configurable talking characters in ASCII art
curl - Get a file from an HTTP, HTTPS or FTP server
ditaa - Convert ASCII diagrams into proper bitmap graphics
exiftool - Perl lib for reading and writing EXIF metadata
fish - User-friendly command-line shell for UNIX-like operating systems
fortune - Infamous electronic fortune-cookie generator
fzf - Command-line fuzzy finder written in Go
git - Distributed revision control system
gotop - Terminal based graphical activity monitor inspired by gtop and vtop
htop - Improved top (interactive process viewer)
imageoptim-cli - CLI for ImageOptim, ImageAlpha and JPEGmini
jq - Lightweight and flexible command-line JSON processor
leiningen - Build tool for Clojure
lolcat - Rainbows and unicorns in your console!
mkcert - Simple tool to make locally trusted development certificates
neofetch - Fast, highly customisable system info script
nginx - HTTP(S) server and reverse proxy, and IMAP/POP3 proxy server
openssh - OpenBSD freely-licensed SSH connectivity tools
pandoc - Swiss-army knife of markup format conversion
pdfcpu - PDF processor written in Go
pdfcrack - PDF files password cracker
pdfgrep - Search PDFs for strings matching a regular expression
rsync - Utility that provides fast incremental file transfer
speedtest-cli - Command-line interface for https://speedtest.net bandwidth tests
starship - Cross-shell prompt for astronauts
tag - Manipulate and query tags on macOS files
tldr - Simplified and community-driven man pages
trash - CLI tool that moves files or folder to the trash
tree - Display directories as trees (with optional color/HTML output)
volta - JavaScript toolchain manager for reproducible environments
wget - Internet file retriever
xmlstarlet - XML command-line utilities
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment