Marty Oehme
0aaca26b0e
Instead of `-P` being a flag for showing history it has become an option whose argument is the number of history entries to show, `-P 4`. To mimic the old behavior use `-P 0`. Added some test coverage for history functionality. Fixes #1.
243 lines
7.3 KiB
Bash
Executable file
243 lines
7.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
bm_version=0.3.0
|
|
# Emoji default database location
|
|
bm_db_location=${BEMOJI_DB_LOCATION:-"${XDG_DATA_HOME:-$HOME/.local/share}/bemoji"}
|
|
# Setting custom emoji list file location:
|
|
# BEMOJI_CUSTOM_LIST=/my/location/emojis.txt
|
|
# Setting custom recent emoji history:
|
|
# BEMOJI_HISTORY_LOCATION=/path/to/my/recents/directory
|
|
bm_state_dir="${BEMOJI_HISTORY_LOCATION:-${XDG_STATE_HOME:-$HOME/.local/state}}"
|
|
bm_history_file="${bm_state_dir}/bemoji-history.txt"
|
|
|
|
# Command to run after user chooses an emoji
|
|
bm_default_cmd="$BEMOJI_DEFAULT_CMD"
|
|
|
|
# Newline after echo
|
|
bm_echo_newline=${BEMOJI_ECHO_NEWLINE:-true}
|
|
# Do not save choices
|
|
bm_private_mode=${BEMOJI_PRIVATE_MODE:-false}
|
|
# Do not sort results
|
|
bm_limit_recent="$BEMOJI_LIMIT_RECENT"
|
|
|
|
# Report usage
|
|
usage() {
|
|
echo "Usage: $(basename "$0") [-t | -c | -e] [-f <filepath> ] [-p] [-P] [-D <choices>]" 1>&2
|
|
echo
|
|
echo "A simple emoji picker. Runs on bemenu/wofi/rofi/dmenu by default."
|
|
echo "Invoked without arguments sends the picked emoji to the clipboard."
|
|
echo
|
|
echo " Command options (can be combined):"
|
|
echo " -t Simulate typing the emoji choice with the keyboard."
|
|
echo " -c Send emoji choice to the clipboard. (default)"
|
|
echo " -e Only echo out the picked emoji."
|
|
echo ""
|
|
echo " Other options:"
|
|
echo " -n Do not print a newline after the picked emoji."
|
|
echo " -p Do not save picked emoji to recent history."
|
|
echo " -P <number> Limit number of recent emoji to display."
|
|
echo " -D <choice> Choose from default lists to download."
|
|
echo " Valid choices: all|none|emoji|math (multiple choices possible)."
|
|
echo " -f <filepath> Use a custom emoji database. Can be a url which will be retrieved."
|
|
echo " -v Display current program version and directory configuration."
|
|
echo " -h Show this help."
|
|
echo
|
|
exit "$1"
|
|
}
|
|
|
|
version() {
|
|
printf "v%s\ndatabase=%s\nhistory=%s\n" "$bm_version" "$bm_db_location" "$bm_history_file"
|
|
exit
|
|
}
|
|
|
|
# Get Options
|
|
while getopts ":f:D:tcenpP:hv" o; do
|
|
case "${o}" in
|
|
f) BEMOJI_CUSTOM_LIST="${OPTARG}" ;;
|
|
t) bm_cmds+=(_typer) ;;
|
|
c) bm_cmds+=(_clipper) ;;
|
|
e) bm_cmds+=(cat) ;;
|
|
n) bm_echo_newline=false ;;
|
|
D) BEMOJI_DOWNLOAD_LIST="${OPTARG}" ;;
|
|
p) bm_private_mode=true ;;
|
|
P) bm_limit_recent="${OPTARG}" ;;
|
|
h) usage 0 ;;
|
|
v) version ;;
|
|
*) usage 1 ;;
|
|
esac
|
|
done
|
|
|
|
prepare_db() {
|
|
# Create list directory
|
|
if [ ! -d "$bm_db_location" ]; then
|
|
mkdir -p "$bm_db_location"
|
|
fi
|
|
|
|
if [ -n "$BEMOJI_DOWNLOAD_LIST" ]; then
|
|
# Populate default lists
|
|
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'none'; then
|
|
printf "Not downloading a default emoji list.\n"
|
|
return
|
|
elif echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'all'; then
|
|
dl_default_emoji
|
|
dl_math_symbols
|
|
return
|
|
else
|
|
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'emoji'; then
|
|
dl_default_emoji
|
|
fi
|
|
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'math'; then
|
|
dl_math_symbols
|
|
fi
|
|
fi
|
|
fi
|
|
if [ -n "$(find "$bm_db_location" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
|
|
dl_default_emoji
|
|
fi
|
|
}
|
|
|
|
dl_default_emoji() {
|
|
local emojis
|
|
emojis=$(curl -sSL "https://unicode.org/Public/emoji/latest/emoji-test.txt")
|
|
printf "%s" "$emojis" | sed -ne 's/^.*; fully-qualified.*# \(\S*\) \S* \(.*$\)/\1 \2/gp' >"$bm_db_location/emojis.txt"
|
|
printf "Downloaded default emoji set.\n"
|
|
}
|
|
dl_math_symbols() {
|
|
curl -sSL "https://unicode.org/Public/math/latest/MathClassEx-15.txt" |
|
|
grep -ve '^#' | cut -d';' -f3,7 | sed -e 's/;/ /' >"$bm_db_location/math.txt"
|
|
printf "Downloaded math symbols set.\n"
|
|
}
|
|
|
|
gather_emojis() {
|
|
if [ -n "$BEMOJI_CUSTOM_LIST" ] && [ -f "$BEMOJI_CUSTOM_LIST" ]; then
|
|
result=$(cat "$BEMOJI_CUSTOM_LIST")
|
|
elif [ -n "$BEMOJI_CUSTOM_LIST" ] && curl -fsSI "$BEMOJI_CUSTOM_LIST" >/dev/null 2>&1; then
|
|
result=$(curl -sSL "$BEMOJI_CUSTOM_LIST")
|
|
else
|
|
result=$(cat "$bm_db_location"/*.txt)
|
|
fi
|
|
|
|
if [ -n "$bm_limit_recent" ] && [ "$bm_limit_recent" -eq 0 ]; then
|
|
printf "%s" "$result"
|
|
return
|
|
fi
|
|
|
|
printf "%s\n%s" "$(get_most_recent "$bm_limit_recent")" "$result" | cat -n - | sort -uk2 | sort -n | cut -f2-
|
|
}
|
|
|
|
get_most_recent() {
|
|
limit=${1}
|
|
recent_file="$bm_history_file"
|
|
if [ ! -f "$recent_file" ]; then
|
|
touch "$recent_file"
|
|
fi
|
|
# TODO improve this messy line
|
|
local result
|
|
result=$(sed -e '/^$/d' "$recent_file" |
|
|
sort |
|
|
uniq -c |
|
|
sort -k1rn |
|
|
sed -e 's/^\s*//' |
|
|
cut -d' ' -f2-)
|
|
if [ -z "$limit" ]; then
|
|
echo "$result"
|
|
else
|
|
echo "$result" | head -n "$limit"
|
|
fi
|
|
}
|
|
|
|
add_to_recent() {
|
|
if [ -z "$1" ]; then return; fi
|
|
if [ ! -d "$bm_state_dir" ]; then
|
|
mkdir -p "$bm_state_dir"
|
|
fi
|
|
echo "$1" >>"$bm_history_file"
|
|
}
|
|
|
|
# Set default clipboard util
|
|
_clipper() {
|
|
if [ -n "$BEMOJI_CLIP_CMD" ]; then
|
|
# shellcheck disable=SC2068
|
|
${BEMOJI_CLIP_CMD[@]}
|
|
elif [ -n "$WAYLAND_DISPLAY" ] && command -v wl-copy >/dev/null 2>&1; then
|
|
wl-copy
|
|
elif [ -n "$DISPLAY" ] && command -v xclip >/dev/null 2>&1; then
|
|
xclip -selection clipboard
|
|
elif [ -n "$DISPLAY" ] && command -v xsel >/dev/null 2>&1; then
|
|
xsel -b
|
|
else
|
|
printf "No suitable clipboard tool found."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Set default typing uti
|
|
_typer() {
|
|
if [ -n "$BEMOJI_TYPE_CMD" ]; then
|
|
# shellcheck disable=SC2068
|
|
${BEMOJI_TYPE_CMD[@]}
|
|
return
|
|
fi
|
|
|
|
totype=$(cat -)
|
|
if [ -n "$WAYLAND_DISPLAY" ] && command -v wtype >/dev/null 2>&1; then
|
|
wtype -s 30 "$totype"
|
|
elif [ -n "$DISPLAY" ] && command -v xdotool >/dev/null 2>&1; then
|
|
xdotool type --delay 30 "$totype"
|
|
else
|
|
printf "No suitable typing tool found."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Set default picker util
|
|
_picker() {
|
|
if [ -n "$BEMOJI_PICKER_CMD" ]; then
|
|
# shellcheck disable=SC2068
|
|
${BEMOJI_PICKER_CMD[@]}
|
|
elif command -v bemenu >/dev/null 2>&1; then
|
|
bemenu -p 🔍 -i -l 20
|
|
elif command -v wofi >/dev/null 2>&1; then
|
|
wofi -p 🔍 -i --show dmenu
|
|
elif command -v rofi >/dev/null 2>&1; then
|
|
rofi -p 🔍 -i -dmenu --kb-custom-1 "Alt+1" --kb-custom-2 "Alt+2"
|
|
elif command -v dmenu >/dev/null 2>&1; then
|
|
dmenu -p 🔍 -i -l 20
|
|
else
|
|
printf "No suitable picker tool found."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
[ -n "$BEMOJI_CUSTOM_LIST" ] || prepare_db
|
|
result=$(gather_emojis | _picker)
|
|
exit_value="$?"
|
|
[ "$bm_private_mode" = true ] || add_to_recent "$result"
|
|
result=$(echo "$result" | grep -o '^\S\+' | tr -d '\n')
|
|
|
|
case "$exit_value" in
|
|
1)
|
|
exit 1
|
|
;;
|
|
0)
|
|
if [ ${#bm_cmds[@]} -eq 0 ]; then
|
|
if [ -n "$bm_default_cmd" ]; then
|
|
# shellcheck disable=SC2068
|
|
echo "$result" | ${bm_default_cmd[@]}
|
|
exit
|
|
fi
|
|
bm_cmds+=(_clipper)
|
|
fi
|
|
for cmd in "${bm_cmds[@]}"; do
|
|
[ "$bm_echo_newline" = true ] && echo_opts= || echo_opts=-n
|
|
echo $echo_opts "$result" | "$cmd"
|
|
done
|
|
;;
|
|
10)
|
|
echo "$result" | _clipper
|
|
;;
|
|
11)
|
|
echo "$result" | _typer
|
|
;;
|
|
esac
|
|
exit
|