commit b1361617e7657bf6e5ff580fe9bff7f003b7cd69 Author: Marty Oehme Date: Wed Dec 1 15:51:37 2021 +0100 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3849f8a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Marty Oehme + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..386a171 --- /dev/null +++ b/README.md @@ -0,0 +1,233 @@ +# bemoji ❤ - Quickly ⛏ your 🌟 + +Emoji picker with support for bemenu/wofi/rofi/dmenu and wayland/X11. + +Will remember your favorite emojis and give you quick access. + +![bemoji picker interface on bemenu](assets/bemenu.png) + +## 📁 Installation + +Option 1. Clone the repository and put the executable somewhere in your path: + +```bash +git clone +chmod +x bemoji/bemoji +mv bemoji/bemoji /usr/local/bin/bemoji +rm -r bemoji +``` + +Option 2. Clone the repository and link the executable to your path: + +```bash +git clone +chmod +x bemoji/bemoji +ln -s bemoji/bemoji /usr/local/bin/bemoji +``` + +Dependencies: + +* One of `bemenu`, `wofi`, `rofi`, `dmenu`, or supplying your own picker. +* One of `wl-copy`, `xclip`, `xsel` or supplying your own clipboard tool. +* One of `wtype`, `xdotool` or supplying your own typing tool. +* `sed`, `grep`, `cut`, `sort`, `uniq`, `tr`, `curl` if using the download functionality. + +To see how to substitute the default choices with your own tools, +see Options below. + +![wofi picker interface](assets/wofi.png) + +## 💿 Usage + +![bemoji help window](assets/help.png) + +Simply execute `bemoji` without any options to set up the default emoji database and let you quickly pick an emoji. +It will be copied to your clipboard for you to paste anywhere. +If you execute `bemoji -t` it will directly type your emoji directly into whatever application is in focus. + +When the emoji list is open you can always press `Alt+1` to send the selected emoji to clipboard and `Alt+2` to type the selected emoji, +regardless of what the default action is set to.[^always] + +[^always]: This functionality currently only works in bemenu and rofi. + +You can also map the picker to a key combination, e.g. + +In `swaywm`, put the following in `~/.config/sway/config`: + +``` +bindsym Mod4+Shift+e exec bemoji -t +``` + +For `i3`, put the same into `~/.config/i3/config`: + +``` +bindsym Mod4+Shift+e exec bemoji -t +``` + +For `riverwm`, put the following in `~/.config/river/init`: + +``` +riverctl map normal $mod+Shift E spawn "bemoji -t" +``` + +In `sxhkd`, put the following into `~/.config/sxhkd/sxhkdrc`: + +``` +super + Shift + e + bemoji -t +``` + +And you can easily type any emoji with the help of `Super+Shift+E`. + +![rofi picker interface](assets/rofi.png) + +## 🧰 Options + +bemoji comes with a couple of options to specify actions, emoji libraries and directories being used. + +### Adding your own emoji + +Simply put your own emoji list into the bemoji data directory. +By default, the directory will be at your `$XDG_DATA_HOME/bemoji` location - +most likely this is `~/.local/share/bemoji`. + +Add any number of `.txt` files containing additional emoji to this directory: + +``` +🫦 Biting lip +🫶 Heart Hands +``` + +The lists *need* to have the format `🙂 description of emoji` with a whitespace separating the emoji and its description. +The description can have as many words and whitespaces as you want. + +### Ignoring the most recent emoji + +By default, bemoji will sort the list it displays by your most frequently and most recently used emoji. +To disable this behavior, execute bemoji like the following: + +```bash +bemoji -P +``` + +This will stop bemoji from re-ordering your emoji lists before displaying them. + +You can also stop bemoji from adding any emoji to your history in the first place: + +```bash +bemoji -p +``` + +This will not add any of the emoji you pick to your recent emojis. +Put both together to completely ignore the recent emoji feature of the program: + +```bash +bemoji -Pp +``` + +Like this, you'll be hiding any recent personal emoji and no one will know that you always type 👄🍆💦. + +The recent list will also contain emoji that are *not* usually on your lists, +so kept in single-use lists for example. +If you don't wish those to show up, make use of these options. + +### Setting custom directories + +By default bemoji stores your recent history in `$XDG_CACHE_HOME/bemoji-history.txt`, +so most often in `~/.cache/bemoji-history.txt` + +You can overwrite the directories bemoji uses for its emoji lists and history files with the following two environment variables: + +``` +BEMOJI_DB_LOCATION=/path/to/my/emoji/directory +BEMOJI_CACHE_LOCATION=/path/to/my/cache/directory +``` + +There are no equivalent commandline arguments to overwrite these two settings. + +### Display one custom emoji list + +A custom emoji list can be supplied as commandline argument `-f` or `BEMOJI_CUSTOM_LIST` environment variable. + +```bash +bemoji -f path/to/my/list.txt +``` + +The list will override the normally presented emoji, +so that only the custom list and recent emoji will be displayed. +To display *only* the emoji list passed in, pass an extra `-P` flag to bemoji. + +The path can also be a weblink which bemoji will download and use: + +``` +bemoji -f "https://raw.githubusercontent.com/jchook/emoji-menu/master/data/emojis.txt" +``` + +### Change the default emoji set + +bemoji downloads emoji for you to use on first invocation. +By default, it only downloads emoji, though you can have it download math symbols as well. +To change this setting, execute bemoji like the following: + +```bash +bemoji -D all +``` + +This will download *all* default sets bemoji knows - which is currently the default emoji list and a long list of math symbols. +Other valid options for this setting are `emoji`, `math`, `none`. + +If set to `none` and no files are in the emoji directory, +bemoji will simply complain and not show anything. + +### Using a custom tool for picking, clipping, typing + +If you want to replace one of the default supported tools with your own you can do this through environment variables: + +```bash +BEMOJI_PICKER_CMD="path/to/your/picker-tool" +BEMOJI_CLIP_CMD="path/to/your/clipboard/tool" +BEMOJI_TYPE_CMD="path/to/your/xdotool" +``` + +This is pretty experimental and you'll have to see how well it works for you. +The setting can not be changed through the commandline alone. + +### Execute a custom command with my emoji + +You can execute bemoji with the `-e` flag with which you tell it not to do anything but echo out the chosen emoji. + +This can be very useful for creating your own little script with it: + +```bash +bemoji -e | cat <(echo -n "https://emojipedia.org/") - | xargs xdg-open +``` + +This snippet will open a wiki page for the picked emoji in your browser. + +Of course, there are many more possibilities. +This is just an example to show how the echo mode works. + +### A list of all environment variables + +What follows is a list of all environment variables bemoji understands, +with their default settings + +```bash +BEMOJI_DB_LOCATION=$XDG_DATA_HOME/bemoji # where the emoji lists reside +BEMOJI_CACHE_LOCATION=$XDG_CACHE_HOME # where the cache file resides +BEMOJI_CUSTOM_LIST="" # the custom emoji list to display +BEMOJI_DOWNLOAD_LIST="" # the default emoji lists to download to database +BEMOJI_DEFAULT_COMMAND= # which command to invoke by default +BEMOJI_PICKER_CMD=bemenu # which picker tool to use +BEMOJI_CLIP_CMD=wl-copy # which clipboard tool to use +BEMOJI_TYPE_CMD=wtype # which typing tool to use (ydotool will NOT work) +BEMOJI_PRIVATE_MODE=false # whether to save new entries +BEMOJI_IGNORE_RECENT=false # whether to display recent entries +``` + +## Issues + +Thanks for checking this program out! ❤ + +If there are any problems, don't hesitate to open an issue. +If you have an idea or improvement, don't hesitate to open a merge request! diff --git a/assets/bemenu.png b/assets/bemenu.png new file mode 100644 index 0000000..41231fd Binary files /dev/null and b/assets/bemenu.png differ diff --git a/assets/help.png b/assets/help.png new file mode 100644 index 0000000..b2c331f Binary files /dev/null and b/assets/help.png differ diff --git a/assets/rofi.png b/assets/rofi.png new file mode 100644 index 0000000..650d11f Binary files /dev/null and b/assets/rofi.png differ diff --git a/assets/wofi.png b/assets/wofi.png new file mode 100644 index 0000000..79f8235 Binary files /dev/null and b/assets/wofi.png differ diff --git a/bemoji b/bemoji new file mode 100755 index 0000000..1d72b62 --- /dev/null +++ b/bemoji @@ -0,0 +1,214 @@ +#!/usr/bin/env sh + +# Wanted features: +# +# - [ ] limit maximum number of recent emoji + +# 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 cache: +# BEMOJI_CACHE_LOCATION=/path/to/my/recents/directory +bm_cache_dir="${BEMOJI_CACHE_LOCATION:-${XDG_CACHE_HOME:-$HOME/.cache}}" +bm_history_file="${bm_cache_dir}/bemoji-history.txt" + +# Command to run after user chooses an emoji +bm_default_cmd=${BEMOJI_DEFAULT_CMD:-'_clipResult'} + +# Do not save choices +bm_private_mode=${BEMOJI_PRIVATE_MODE:-false} +# Do not sort results +bm_ignore_recent=${BEMOJI_IGNORE_RECENT:-false} + +# Report usage +usage() { + echo "Usage: $(basename "$0") [-t | -c | -e] [-f ] [-p] [-P] [-D all|none|emoji]" 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 " -f Use a custom emoji database. Can be a url which will be retrieved." + echo " -t Simulate typing the emoji choice with the keyboard." + echo " -c Send emoji choice to the clipboard. (default)" + echo " -p Do not save picked emoji to recent history." + echo " -P Do not order emoji by recently used." + echo " -e Only echo out the picked emoji." + echo " -D Choose specific default lists to download if none found locally." + echo + exit "$1" +} + +# Get Options +while getopts ":f:D:tcepPh" o; do + case "${o}" in + f) BEMOJI_CUSTOM_LIST="${OPTARG}" ;; + t) bm_default_cmd=_typeResult ;; + c) bm_default_cmd=_clipResult ;; + e) bm_default_cmd=_echo ;; + D) BEMOJI_DOWNLOAD_LIST="${OPTARG}" ;; + p) bm_private_mode=true ;; + P) bm_ignore_recent=true ;; + h) usage 0 ;; + *) usage 1 ;; + esac +done + +prepare_db() { + # Create list directory + if [ ! -d "$bm_db_location" ]; then + mkdir -p "$bm_db_location" + fi + + if [ -n "$(find "$bm_db_location" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then + # Populate default lists + if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'none'; then + printf "No emoji list found, but set to not download any default lists." + exit 1 + elif echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'all'; then + dl_default_emoji + dl_math_symbols + return + fi + if [ -z "$BEMOJI_DOWNLOAD_LIST" ] || 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 +} + +dl_default_emoji() { + curl -sSL "https://unicode.org/Public/emoji/14.0/emoji-test.txt" | + sed -ne 's/^.*; fully-qualified.*# \(\S*\) \S* \(.*$\)/\1 \2/gp' >"$bm_db_location/emojis.txt" + printf "Downloaded default emoji set." +} +dl_math_symbols() { + curl -sSL "https://unicode.org/Public/math/latest/MathClassEx-15.txt" | + grep -ve '^#' | cut -d';' -f3,7 --output-delimiter=' ' >"$bm_db_location/math.txt" + printf "Downloaded math symbols set." +} + +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 [ "$bm_ignore_recent" = true ]; then + printf "%s" "$result" + else + printf "%s\n%s" "$(get_most_recent)" "$result" | cat -n - | sort -uk2 | sort -n | cut -f2- + fi +} + +get_most_recent() { + recent_file="$bm_history_file" + if [ ! -f "$recent_file" ]; then + touch "$recent_file" + fi + # TODO improve this messy line + cat "$recent_file" | + sed -e '/^$/d' | + sort | + uniq -c | + sort -rn | + sed -e 's/^\s*//' | + cut -d' ' -f2- +} + +add_to_recent() { + if [ -z "$1" ]; then return; fi + if [ ! -d "$bm_cache_dir" ]; then + mkdir -p "$bm_cache_dir" + fi + echo "$1" >>"$bm_history_file" +} + +# Set default clipboard util +_clipper() { + if [ -n "$BEMOJI_CLIP_CMD" ]; then + "${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() { + totype=$(cat -) + if [ -n "$BEMOJI_TYPE_CMD" ]; then + "${BEMOJI_TYPE_CMD[@]}" + elif [ -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 "$totype" --delay 30 + else + printf "No suitable typing tool found." + exit 1 + fi +} + +# Set default picker util +_picker() { + if [ -n "$BEMOJI_PICKER_CMD" ]; then + "${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 🔍 -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 +} + +# Type result using xdotool +_typeResult() { + cat - | _typer +} + +_clipResult() { + cat - | _clipper +} + +[ -n "$BEMOJI_CUSTOM_LIST" ] || prepare_db +result=$(gather_emojis | _picker) +exit_value="$?" +[ "$bm_private_mode" = true ] || add_to_recent "$result" +result=$(echo "$result" | grep -oP '^[^\s]+' | tr -d '\n') + +case "$exit_value" in +1) + exit + ;; +0) + if [ "$bm_default_cmd" = "_echo" ]; then + echo "$result" + exit + fi + echo "$result" | "$bm_default_cmd" + ;; +10) + echo "$result" | _clipResult + ;; +11) + echo "$result" | _typeResult + ;; +esac +exit