Compare commits

...

23 Commits
v0.3.0 ... main

Author SHA1 Message Date
Marty Oehme ab10547336
📖 Add example for setting manual picker to README 2024-04-17 10:20:57 +02:00
Marty Oehme 1cf9971d8b
📖 Bump version
ci/woodpecker/push/woodpecker Pipeline was successful Details
2024-02-22 13:46:45 +01:00
Marty Oehme 46fa824d42
🐛 Remove deprecated CI instruction 2024-02-22 13:46:45 +01:00
Marty Oehme 551e3468d8
📖 Bump license copyright year
ci/woodpecker/push/woodpecker Pipeline was successful Details
Bumping the year again. I am honestly not entirely sure what the best or
correct way to display this is - so I am simply copying what the `curl`
project is doing and stating the whole period of me working on it.

Perhaps one day (should we get more contributors or much more popular)
it may also make sense to copy its `THANKS` file to keep a stable copy
of my contributing helpers.
2024-01-11 11:28:44 +01:00
Marty Oehme cb3d8fd5d6
🐛 Remove deprecated woodpecker ci conditions
Tag condition (when: event: tag) filters are not generalized to `ref`
instead of the old `tag` key. This switches them to the new version.

See
https://woodpecker-ci.org/docs/usage/workflow-syntax#when---conditional-execution
2024-01-11 11:17:47 +01:00
Marty Oehme e14010eb53
🐛 Print user messages to stderr (#27)
ci/woodpecker/manual/woodpecker Pipeline was successful Details
Previously, any messages only intended for the user (status messages,
warnings, errors) were sent over stdout. The actual emoji items are also
sent to the pickers over stdout so they would sometimes pick up the
messages and show them as an option to pick. If history is enabled, we
then also save the falsely included items there to forever display as an
option.

This commit changes internal messages to all be sent over stderr
instead, so they should not be picked up by any external programs we
hand off to.
2024-01-11 10:58:11 +01:00
Marty Oehme 7b5b3e6e46
🦊 Migrate major woodpecker ci version
Migrated to newer woodpecker version requiring different pipeline
naming scheme, see https://woodpecker-ci.org/docs/migrations.
2024-01-11 09:25:23 +01:00
Laureηt b97c09828d
Add support for fuzzel desktop executor
ci/woodpecker/push/woodpecker Pipeline was successful Details
Fuzzel is a wayland-native picker which support dmenu-like picking based
on standard input.
---------

Co-authored-by: Marty Oehme <marty.oehme@gmail.com>
2023-11-28 10:53:31 +01:00
Jesse Cooke 74af60c3f7
Add support for ilia desktop executor
ci/woodpecker/push/woodpecker Pipeline was successful Details
Ilia is used by Regolith Linux (Ubuntu+i3/sway).

Ilia has a slightly different presentation and prompt setup than other
pickers, and it makes more sense to use the given GTK icon instead of
the emoji character since that is what it seems to support.

Nicely explained by @jc00ke here:
https://github.com/marty-oehme/bemoji/pull/21#discussion_r1306212419

With the growing amount of picker tools supported out of the box
it seems more practical to have them together in a simple list
that can grow and through which we can always iterate instead
of a cumbersome growing if-else chain.
This commit also refactors the pick tool selection to be stored in
a bash hash map instead.
2023-09-14 17:14:39 +02:00
Marty Oehme 011fcdefdd
📖 Update usage screenshot
ci/woodpecker/push/woodpecker Pipeline was successful Details
2023-08-26 14:58:45 +02:00
Marty Oehme d44cbf5b74
Add long-form option parsing
ci/woodpecker/push/woodpecker Pipeline was successful Details
So far we could only add single-letter (POSIX) options: `-e`, `-n` and
so forth. Since we will run out of alphabet at some point, this commit
introduces parsing of multi-letter long-form (gnu) options (plus any
modern application should really support it anyways):
`--echo`, `--noline`.

Additionally, we support supplying long-form options that supply a value
both in the spaced (`--hist-limit 0`) and the equals (`--hist-limit=0`)
forms. Short, long, spaced, equals can be mixed and matched between
freely.

Lastly, we retain the ability to concatenate short options as before
(`-ne` is valid, as is `-P0` for the respective options above).

This should cover all bases and does not complicate the code too much to
keep a coherent overview.

Changed several code samples in the documentation to make
use of short- or long-form options to point out
possibility.
2023-08-26 14:37:44 +02:00
Marty Oehme 6c037a5771
📖 Add reference to stable and git archlinux versions
ci/woodpecker/push/woodpecker Pipeline was successful Details
Since there is now both a -git version and a stable version in the
AUR we make a small note for both in the installation documentation.
2023-08-25 20:55:39 +02:00
Marty Oehme a8256100f9
🐛 Fix release automation naming scheme
Names for tags in this repo start with a `v` (e.g. `v0.3.1`) but the
release automation did not know about this and would create duplicate
tags without the preceding letter.
2023-08-25 20:47:14 +02:00
Marty Oehme e720343ffc
Add ability to download nerdfont symbols (#10)
ci/woodpecker/push/woodpecker Pipeline was successful Details
Same as the other symbol download options, this one takes a list of all
nerdfont icons and wrangles them into shape to be usable with the emoji
picker. Can be used by invoking `bemoji -D nerd` or `bemoji -D all`.

Fixes #10.
2023-05-01 16:03:09 +02:00
Marty Oehme 54b72e583b
📖 Bump license copyright year
ci/woodpecker/push/woodpecker Pipeline was successful Details
2023-04-30 18:28:23 +02:00
Marty Oehme 0aaca26b0e
BREAKING: Add ability to limit recent emoji shown (#1)
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.
2023-04-30 18:22:44 +02:00
Marty Oehme 6b39e5e05a
🐛 Create dist package contents at root directory 2023-04-12 11:22:00 +02:00
Marty Oehme 07de35e92f
📖 Fix riverwm usage instructions assuming variable
Usage instructions for mapping the picker in riverwm falsely assumed the
super key to already be mapped to a `$mod` variable. This commit fixes
it to replace mention of the variable with the key name itself.
2023-04-11 23:25:41 +02:00
Marty Oehme 941dd4aaea
📖 Change AUR instructions to fit multiple packages
ci/woodpecker/push/woodpecker Pipeline was successful Details
Generalized AUR package installation instructions slightly to take note
of the fact that there are multiple AUR packages available for bemoji.

Thanks to @thayne for packaging up the semver release version of bemoji
for the AUR!
2023-04-11 23:20:03 +02:00
Marty Oehme 56ae0f1bab
🐛 Pass through stdin to custom typing tool (#19)
Previously, stdin contents were consumed and then not passed through to
the typing tool. With this commit, they are correctly passed to any
custom tool's stdin.

Fixes #19.
2023-04-11 23:00:19 +02:00
Marty Oehme 71d5dc455d
🦊 Exit status 1 on cancelled selection (#20)
When making no selection, i.e. cancelling during the selection process
the program will return status code 1, whereas before it would carry the
same return code as when making an emoji selection.

Fixes #20.
2023-04-11 22:33:26 +02:00
Marty Oehme 32fc9f45dd
🦊 Update emoji url to latest version (#18)
Point url to grab emoji from to latest version of emoji list, which
should automatically point to upcoming versions as well.

Fixes #18.
2023-04-11 22:00:45 +02:00
Marty Oehme 59d436a944
🦊 BREAKING: Use new XDG Base specification for state (#5)
ci/woodpecker/push/woodpecker Pipeline was successful Details
Switched the history from using the XDG_CACHE_HOME directory by default
to use XDG_STATE_HOME by default.

This makes sense since cache can (and should be prepared to) be wiped at
any moment and the program functionality should not be hindered by this.
Since we need to retain history through such wipes the newly introduced
state directory is the perfect match for keeping the history file in.

This does constitute a breaking change for existing histories which need
to be moved to the new directory if they made use of the old cache
directory.

Concurrent with this we are renaming `XDG_CACHE_LOCATION` environment
variable to `XDG_HISTORY_LOCATION` so this is a second breaking change
for those using a custom location for their histories.

This change attempts to make the naming scheme coherent and remove some
left-over naming cruft from the old location being the cache directory.

This provides one of the larger changes to the program so far.

Fixes #5.
2022-11-19 15:03:14 +01:00
11 changed files with 413 additions and 129 deletions

View File

@ -1,22 +1,24 @@
pipeline:
steps:
test:
image: bats/bats
commands:
- /opt/bats/bin/bats test
release-prep: # prepare changelog and version information for release candidate
release-prep:
# prepare changelog and version information for release candidate
when:
event: tag
tag: v*
ref: refs/tags/v*
image: alpine
commands:
- sed -ne 's/bm_version=\(.*\)/\1/p' bemoji > NEWEST_VERSION.txt
- awk '/^## \[\d/{p++} p==2{print; exit} p>=1' CHANGELOG.md | head -n -1 | tail -n+3 > NEWEST_CHANGES.txt
versioncompare: # ensure we correctly bumped versions
versioncompare:
# ensure we correctly bumped versions
when:
event: tag
tag: v*
ref: refs/tags/v*
image: alpine
secrets: [ github_release_token, github_repo ]
commands:
@ -33,7 +35,7 @@ pipeline:
build:
when:
event: tag
tag: v*
ref: refs/tags/v*
image: savant/md2man
commands:
- apk update && apk add zip
@ -42,15 +44,15 @@ pipeline:
- cp bemoji build
- md2man -in README.md -out bemoji.1 && gzip bemoji.1
- cp LICENSE README.md bemoji.1.gz build/doc
- tar -czvf bemoji-$BM_VERSION.tar.gz build/*
- zip -r bemoji-$BM_VERSION.zip build/*
- mv bemoji-$BM_VERSION.tar.gz bemoji-$BM_VERSION.zip dist
- cd build || exit 1
- tar -czvf bemoji-$BM_VERSION.tar.gz *
- zip -r bemoji-$BM_VERSION.zip *
- mv bemoji-$BM_VERSION.tar.gz bemoji-$BM_VERSION.zip ../dist
release-gitea:
group: release
when:
event: tag
tag: v*
ref: refs/tags/v*
image: plugins/gitea-release
settings:
api_key:
@ -63,14 +65,14 @@ pipeline:
release-github:
when:
event: tag
tag: v*
ref: refs/tags/v*
image: alpine
secrets: [ github_release_token, github_repo ]
commands:
- apk add file jq curl
- BM_VERSION=$(cat NEWEST_VERSION.txt)
- BM_CHANGED=$(sed -e 's|#||g' -e 's|^.*$|\0 <br />|' NEWEST_CHANGES.txt) # display newlines workaround
- echo "{\"tag_name\":\"$BM_VERSION\",\"target_commitish\":\"main\",\"name\":\"$BM_VERSION\",\"body\":\"$BM_CHANGED\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}" > data.json
- echo "{\"tag_name\":\"v${BM_VERSION}\",\"target_commitish\":\"main\",\"name\":\"v${BM_VERSION}\",\"body\":\"$BM_CHANGED\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}" > data.json
- "response=$(curl -X POST -H \"Accept:\\ application/vnd.github+json\" -H \"Authorization:\\ Bearer $GITHUB_RELEASE_TOKEN\" https://api.github.com/repos/$GITHUB_REPO/releases -d \"@data.json\")"
- "uploadurl=$(echo $response | jq -r '.upload_url' | cut -d'{' -f1)"
- "[ $uploadurl = null ] && { echo $response; exit 1; }"

View File

@ -19,6 +19,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- ### Security -->
## [0.4.0] - 2024-02-22
### Added
- Add default support for `fuzzel` wayland-native picker tool
- Add default support for `ilia` gtk-based picker tool, used by default in Regolith Linux
- Pass through return code 1 from selection tool
- (!) Number of displayed recent emoji can be set with `-P` option:
This replaces previous `-P` history flag toggle. Use number to set amount of recent
entries to display, `-P3`. To completely hide history use `-P0`.
- Add nerdfont emoji set download with `-D nerd`
- Add parsing for long-form options (`--private` instead of `-p` and so on):
Options requiring a value can be given both in space-separated (`--hist-limit 2`)
and equals-separated (`--hist-limit=2`) versions. POSIX option concatenation still
works (`-ne` to echo without newline).
### Changed
- (!) History uses `XDG_STATE_HOME` directory by default:
This constitutes a break in behavior if you relied a lot on your pick history in the default
location. To retain your old history file, simply move it from the old cache directory
(`~/.cache/bemoji-history.txt` by default) to the new one (`~/.local/state/bemoji-history.txt`
by default).
- (!) `XDG_CACHE_LOCATION` renamed to `XDG_HISTORY_LOCATION` to better signify its purpose
### Fixed
- Always download from newest emoji list url
- Pass selection to custom typing tools through stdin
- Pass info messages to stderr to avoid passing to picker tools
## [0.3.0] - 2022-11-10
### Added

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Marty Oehme
Copyright (c) 2021 - 2024 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

View File

@ -12,7 +12,7 @@ Will remember your favorite emojis and give you quick access.
### Dependencies
* One of `bemenu`, `wofi`, `rofi`, `dmenu`, or supplying your own picker.
* One of `bemenu`, `wofi`, `rofi`, `dmenu`, `ilia`, `fuzzel` 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.
@ -43,10 +43,10 @@ ln -s bemoji/bemoji /usr/local/bin/bemoji
### Arch Linux
On Arch Linux, bemoji has been packaged for the [AUR](https://aur.archlinux.org/packages/bemoji-git) so it can be installed manually from here or easily with your preferred AUR helper, e.g.:
On Arch Linux, bemoji has been packaged for the [AUR](https://aur.archlinux.org/packages?K=bemoji) so it can be installed manually from here or easily with your preferred AUR helper, e.g.:
```bash
paru -S bemoji-git
paru -S bemoji # or bemoji-git
```
## 💿 Usage
@ -78,7 +78,7 @@ 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"
riverctl map normal Mod4+Shift E spawn "bemoji -t"
```
In `sxhkd`, put the following into `~/.config/sxhkd/sxhkdrc`:
@ -118,40 +118,51 @@ By default, bemoji will sort the list it displays by your most frequently and mo
To disable this behavior, execute bemoji like the following:
```bash
bemoji -P
bemoji --hist-limit 0
```
This will stop bemoji from re-ordering your emoji lists before displaying them.
This will stop bemoji from adding recently used emoji before displaying the list.
You can also stop bemoji from adding any emoji to your history in the first place:
```bash
bemoji -p
bemoji --private
```
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:
Put both together to completely ignore the recent emoji feature of the program
(these are the equivalent short versions of the options above):
```bash
bemoji -Pp
bemoji -p -P0
```
Like this, you'll be hiding any recent personal emoji and no one will know that you always type 👄🍆💦.
To limit the number of your recently used emoji that are shown without hiding them completely simply increase the number to however many you wish to display.
For example, to display only the top 4 recently used emoji:
```bash
bemoji --hist-limit 4
```
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
### Setting custom directories and editing history
By default bemoji stores your recent history in `$XDG_CACHE_HOME/bemoji-history.txt`,
so most often in `~/.cache/bemoji-history.txt`
By default bemoji stores your recent history in `$XDG_STATE_HOME/bemoji-history.txt`,
so most often in `~/.local/state/bemoji-history.txt`
You can edit this file in any text editor to change your recent history,
removing, adding or changing the emoji appearing there.
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
BEMOJI_HISTORY_LOCATION=/path/to/my/state/directory
```
There are no equivalent commandline arguments to overwrite these two settings.
@ -161,7 +172,7 @@ There are no equivalent commandline arguments to overwrite these two settings.
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
bemoji --file path/to/my/list.txt
```
The list will override the normally presented emoji,
@ -174,24 +185,24 @@ 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"
```
### Download additional emoji set
### Download additional emoji sets
bemoji automatically downloads an emoji list for you to use on first invocation.
By default, it only downloads emoji, though you can have it download math symbols as well.
By default, it only downloads emoji, though you can have it download math symbols and nerdfont icons as well.
To download additional sets, execute bemoji like the following:
```bash
bemoji -D all
bemoji --download 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`.
This will download *all* default sets bemoji knows - which is currently the default emoji list, nerd font icons, and a long list of math symbols.
Other valid options for this setting are `emoji`, `math`, `nerd`, `none`.
```bash
bemoji -D "math emoji"
bemoji -D "math emoji nerd"
```
The above command is equivalent as you can mention multiple sets you want downloaded.
The above command is equivalent to the previous `all` as you can mention multiple sets you want downloaded.
If set to `none` and no files are in the emoji directory,
bemoji will complain and not show anything.
@ -222,7 +233,15 @@ 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 candidate list (in the case of picker tool) or the picked selection are passed to the tools through stdin.
For example, to manually invoke fuzzel with no extra options as the picker for bemoji you would use:
```bash
BEMOJI_PICKER_CMD="fuzzel -d" bemoji
```
This is somewhat experimental still 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
@ -232,7 +251,7 @@ You can execute bemoji with the `-e` flag with which you tell it not to do anyth
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
bemoji --echo | cat <(echo -n "https://emojipedia.org/") - | xargs xdg-open
```
This snippet will open a wiki page for the picked emoji in your browser.
@ -246,16 +265,16 @@ 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_DB_LOCATION="$XDG_DATA_HOME/bemoji" # where the emoji lists reside
BEMOJI_HISTORY_LOCATION="$XDG_STATE_HOME" # where the state 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=<clip-tool> # 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_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
BEMOJI_LIMIT_RECENT="" # whether to display recent entries
BEMOJI_ECHO_NEWLINE=true # whether to end the output with a newline character
```
@ -271,7 +290,12 @@ If you have an idea or improvement, don't hesitate to open a merge request!
This project makes use of [bash-bats](https://github.com/bats-core/bats-core) (community fork) to test some of its functionality.
To run the tests locally, simply execute `./test/bats/bin/bats test`.
To run the tests locally:
```
git submodule init
git submodule update
./test/bats/bin/bats test
```
I would suggest running the test suite in docker instead, just to minimize the possibility of something going awry and borking up your local file system.
To run the tests in a docker suite, execute `docker run --rm -it -v "$PWD:/code" bats/bats:latest /code/test`
To run the tests in a docker suite, execute `docker run --rm -it -v "$PWD:/code" bats/bats:latest /code/test` after initializing the git submodules as listed above.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 241 KiB

229
bemoji
View File

@ -1,14 +1,14 @@
#!/usr/bin/env bash
bm_version=0.3.0
bm_version=0.4.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 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"
# 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"
@ -18,31 +18,40 @@ bm_echo_newline=${BEMOJI_ECHO_NEWLINE:-true}
# Do not save choices
bm_private_mode=${BEMOJI_PRIVATE_MODE:-false}
# Do not sort results
bm_ignore_recent=${BEMOJI_IGNORE_RECENT:-false}
bm_limit_recent="$BEMOJI_LIMIT_RECENT"
declare -A default_pickers=(
["bemenu"]="bemenu -p 🔍 -i -l 20"
["wofi"]="wofi -p 🔍 -i --show dmenu"
["rofi"]="rofi -p 🔍 -i -dmenu --kb-custom-1 "Alt+1" --kb-custom-2 "Alt+2""
["dmenu"]="dmenu -p 🔍 -i -l 20"
["ilia"]="ilia -n -p textlist -l 'Emoji' -i desktop-magnifier"
["fuzzel"]="fuzzel -d -p 🔍"
)
# 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 Do not order emoji by recently used."
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"
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, --type Simulate typing the emoji choice with the keyboard."
echo " -c, --clip Send emoji choice to the clipboard. (default)"
echo " -e, --echo Only echo out the picked emoji."
echo ""
echo " Other options:"
echo " -n, --noline Do not print a newline after the picked emoji."
echo " -p, --private Do not save picked emoji to recent history."
echo " -P, --hist-limit <number> Limit number of recent emoji to display."
echo " -D, --download <choice> Choose from default lists to download."
echo " Valid choices: all|none|emoji|math|nerd (multiple choices possible)."
echo " -f, --file <filepath> Use a custom emoji database. Can be a url which will be retrieved."
echo " -v, --version Display current program version and directory configuration."
echo " -h, --help Show this help."
echo
exit "$1"
}
version() {
@ -50,22 +59,72 @@ version() {
exit
}
# Get Options
while getopts ":f:D:tcenpPhv" 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_ignore_recent=true ;;
h) usage 0 ;;
v) version ;;
*) usage 1 ;;
esac
done
msg() {
# Outputs a message to stderr, to be used for info, warning and error messages.
printf "%s\n" "$1" >&2
}
parse_cli() {
while getopts cD:ef:hnpP:tv-: arg "$@"; do
case "$arg" in
c) bm_cmds+=(_clipper) ;;
D) _opt_set_download_list "${OPTARG}" ;;
e) bm_cmds+=(cat) ;;
f) _opt_set_custom_list "${OPTARG}" ;;
h) usage 0 ;;
n) bm_echo_newline=false ;;
p) bm_private_mode=true ;;
P) _opt_set_hist_limit "${OPTARG}" ;;
t) bm_cmds+=(_typer) ;;
v) version ;;
-)
LONG_OPTARG="${OPTARG#*=}"
case "$OPTARG" in
clip) bm_cmds+=(_clipper) ;;
download=?*) _opt_set_download_list "${LONG_OPTARG}" ;;
download*)
_opt_set_download_list "${*:$OPTIND:1}"
OPTIND=$((OPTIND + 1))
;;
echo) bm_cmds+=(cat) ;;
file=?*) _opt_set_custom_list "${LONG_OPTARG}" ;;
file*)
_opt_set_custom_list "${*:$OPTIND:1}"
OPTIND=$((OPTIND + 1))
;;
help) usage 0 ;;
noline) bm_echo_newline=false ;;
private) bm_private_mode=true ;;
hist-limit=?*) _opt_set_hist_limit "${LONG_OPTARG}" ;;
hist-limit*)
_opt_set_hist_limit "${*:$OPTIND:1}"
OPTIND=$((OPTIND + 1))
;;
type) bm_cmds+=(_typer) ;;
version) version ;;
'') break ;;
*)
echo "Unknown option: ${OPTARG}" 1>&2
usage 1
;;
esac
;;
\?) exit 2 ;;
esac
done
shift $((OPTIND - 1))
OPTIND=1
}
_opt_set_custom_list() {
BEMOJI_CUSTOM_LIST="$1"
}
_opt_set_download_list() {
BEMOJI_DOWNLOAD_LIST="$1"
}
_opt_set_hist_limit() {
bm_limit_recent="$1"
}
prepare_db() {
# Create list directory
@ -76,11 +135,12 @@ prepare_db() {
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"
msg "Not downloading a default emoji list."
return
elif echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'all'; then
dl_default_emoji
dl_math_symbols
dl_nerd_symbols
return
else
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'emoji'; then
@ -89,6 +149,9 @@ prepare_db() {
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'math'; then
dl_math_symbols
fi
if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'nerd'; then
dl_nerd_symbols
fi
fi
fi
if [ -n "$(find "$bm_db_location" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
@ -98,14 +161,21 @@ prepare_db() {
dl_default_emoji() {
local emojis
emojis=$(curl -sSL "https://unicode.org/Public/emoji/14.0/emoji-test.txt")
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"
msg "Downloaded default emoji set."
}
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"
msg "Downloaded math symbols set."
}
dl_nerd_symbols() {
local nerd all
nerd=$(curl -sSL "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css")
all+=$(printf "%s" "$nerd" | sed -ne '/\.nf-/p' -e '/\s*[^_]content:/p' | sed -e 'N;s/^\.nf-\(.*\):before.* content: \"\\\(.*\)\";/\\U\2 \1/')
echo -e "$all" > "$bm_db_location/nerdfont.txt"
msg "Downloaded nerdfont symbols set."
}
gather_emojis() {
@ -117,31 +187,39 @@ gather_emojis() {
result=$(cat "$bm_db_location"/*.txt)
fi
if [ "$bm_ignore_recent" = true ]; then
if [ -n "$bm_limit_recent" ] && [ "$bm_limit_recent" -eq 0 ]; then
printf "%s" "$result"
else
printf "%s\n%s" "$(get_most_recent)" "$result" | cat -n - | sort -uk2 | sort -n | cut -f2-
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
sed -e '/^$/d' "$recent_file" |
local result
result=$(sed -e '/^$/d' "$recent_file" |
sort |
uniq -c |
sort -rn |
sort -k1rn |
sed -e 's/^\s*//' |
cut -d' ' -f2-
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_cache_dir" ]; then
mkdir -p "$bm_cache_dir"
if [ ! -d "$bm_state_dir" ]; then
mkdir -p "$bm_state_dir"
fi
echo "$1" >>"$bm_history_file"
}
@ -158,23 +236,26 @@ _clipper() {
elif [ -n "$DISPLAY" ] && command -v xsel >/dev/null 2>&1; then
xsel -b
else
printf "No suitable clipboard tool found."
msg "No suitable clipboard tool found."
exit 1
fi
}
# Set default typing uti
# Set default typing util
_typer() {
totype=$(cat -)
if [ -n "$BEMOJI_TYPE_CMD" ]; then
# shellcheck disable=SC2068
${BEMOJI_TYPE_CMD[@]}
elif [ -n "$WAYLAND_DISPLAY" ] && command -v wtype >/dev/null 2>&1; then
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."
msg "No suitable typing tool found."
exit 1
fi
}
@ -184,20 +265,22 @@ _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
return
fi
for tool in "${!default_pickers[@]}"; do
if command -v "$tool" >/dev/null 2>&1; then
${default_pickers[$tool]}
return
fi
done
msg "No suitable picker tool found."
exit 1
}
parse_cli "$@"
[ -n "$BEMOJI_CUSTOM_LIST" ] || prepare_db
result=$(gather_emojis | _picker)
exit_value="$?"
@ -206,7 +289,7 @@ result=$(echo "$result" | grep -o '^\S\+' | tr -d '\n')
case "$exit_value" in
1)
exit
exit 1
;;
0)
if [ ${#bm_cmds[@]} -eq 0 ]; then

View File

@ -15,8 +15,8 @@ setup() {
# set up small default set of test emoji for each test
export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database"
export BEMOJI_CACHE_LOCATION="$BATS_TEST_TMPDIR/cache"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_CACHE_LOCATION"
export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION"
cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt"
}
@ -54,6 +54,11 @@ setup() {
typing result"
}
@test "Passes selection to custom typer tool through stdin" {
BEMOJI_TYPE_CMD="cat -" run bemoji -t 3>&-
assert_output "❤️"
}
@test "Runs custom default command" {
BEMOJI_DEFAULT_CMD="echo my custom command" run bemoji 3>&-
assert_output "my custom command"
@ -64,6 +69,11 @@ typing result"
assert_output "my clipping"
}
@test "Returns status code 1 on picker status code 1" {
BEMOJI_PICKER_CMD="return 1" run bemoji -e 3>&-
assert_failure 1
}
@test "Prints output with newline by default" {
bats_require_minimum_version 1.5.0
BEMOJI_PICKER_CMD="echo heart" run --keep-empty-lines -- bemoji -e
@ -75,3 +85,29 @@ typing result"
BEMOJI_PICKER_CMD="echo heart" run --keep-empty-lines -- bemoji -ne
assert_output --regexp '^heart$'
}
@test "Understands long-form options" {
run bemoji --help
assert_success
assert_output --partial "A simple emoji picker."
}
@test "Understands long-form equals values" {
BEMOJI_CLIP_CMD="echo heart" run bemoji --hist-limit=0
assert_success
}
@test "Understands long-form spaced values" {
BEMOJI_CLIP_CMD="echo heart" run bemoji --hist-limit 0
assert_success
}
@test "Understands short-form spaced values" {
BEMOJI_CLIP_CMD="echo heart" run bemoji -P 0
assert_success
}
@test "Can concatenate short-form options and values" {
BEMOJI_CLIP_CMD="echo heart" run bemoji -neP0
assert_success
}

View File

@ -15,8 +15,8 @@ setup() {
# set up small default set of test emoji for each test
export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database"
export BEMOJI_CACHE_LOCATION="$BATS_TEST_TMPDIR/cache"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_CACHE_LOCATION"
export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION"
cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt"
}
@ -38,8 +38,8 @@ database=$BATS_TEST_TMPDIR/xdb-db/bemoji
}
@test "sets XDG directory for history by default" {
unset BEMOJI_CACHE_LOCATION
export XDG_CACHE_HOME="$BATS_TEST_TMPDIR/xdb-cache"
unset BEMOJI_HISTORY_LOCATION
export XDG_STATE_HOME="$BATS_TEST_TMPDIR/xdb-cache"
run bemoji -v
assert_output --regexp "
history=$BATS_TEST_TMPDIR/xdb-cache/bemoji-history.txt$"
@ -54,10 +54,10 @@ database=$HOME/.local/share/bemoji
}
@test "falls back to default history location if no XDG found" {
unset BEMOJI_CACHE_LOCATION
unset BEMOJI_HISTORY_LOCATION
run bemoji -v
assert_output --regexp "
history=$HOME/.cache/bemoji-history.txt$"
history=$HOME/.local/state/bemoji-history.txt$"
}
@test "BEMOJI_DB_LOCATION sets correct db directory" {
@ -67,8 +67,8 @@ database=$BATS_TEST_TMPDIR/database
"
}
@test "BEMOJI_CACHE_LOCATION sets correct cache directory" {
@test "BEMOJI_HISTORY_LOCATION sets correct history directory" {
run bemoji -v
assert_output --regexp "
history=$BATS_TEST_TMPDIR/cache/bemoji-history.txt$"
history=$BATS_TEST_TMPDIR/history/bemoji-history.txt$"
}

View File

@ -38,3 +38,11 @@ emoji2 picked up"
assert_equal "$outcome" "Σ GREEK CAPITAL LETTER SIGMA"
unstub curl
}
@test "Runs nerdfont download on -D nerd option" {
stub curl \
"printf 'meangingless\nafiller lines\n.nf-md-pipe_wrench:before { \n content: \"\\\f1354\";\n }'"
run bemoji -D nerd 3>&-
outcome=$(cat "$BEMOJI_DB_LOCATION/nerdfont.txt")
assert_equal "$outcome" "󱍔 md-pipe_wrench"
unstub curl
}

43
test/bemoji_errors.bats Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
setup_file() {
# make bemoji executable from anywhere relative to current testfile
TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$TEST_DIR/..:$PATH"
}
setup() {
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
# set up small default set of test emoji for each test
export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database"
export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION"
cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt"
# these tests require stdout to be separated from stderr
# such run flags were only introduced in recent bats version
bats_require_minimum_version 1.5.0
}
@test "Prints clipper error to stderr" {
BEMOJI_PICKER_CMD="echo hi" run --separate-stderr bemoji 3>&-
assert_output ""
output="$stderr"
assert_output "No suitable clipboard tool found."
}
@test "Prints picker error to stderr" {
run --separate-stderr bemoji 3>&-
assert_output ""
output="$stderr"
assert_output "No suitable picker tool found."
}
@test "Prints typer error to stderr" {
BEMOJI_PICKER_CMD="echo hi" run --separate-stderr bemoji -t 3>&-
assert_output ""
output="$stderr"
assert_output "No suitable typing tool found."
}

57
test/bemoji_history.bats Normal file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
setup_file() {
# make bemoji executable from anywhere relative to current testfile
TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
PATH="$TEST_DIR/..:$PATH"
}
setup() {
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
# mock out interactive picker for static emoji return
export BEMOJI_PICKER_CMD="echo ❤️"
# set up small default set of test emoji for each test
export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database"
export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history"
mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION"
cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt"
}
@test "sorts by frecency" {
echo -e "there\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt"
echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt"
BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji 3>&-
assert_output "hellotheredatabase"
}
@test "history limiting uses sorted results" {
echo -e "zany\nmy\nisee\nonomatopeia" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt"
echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt"
BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 1 3>&-
assert_output "iseedatabase"
}
@test "history limiting takes frecency into account" {
echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt"
echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt"
BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 1 3>&-
assert_output "hellodatabase"
}
@test "-P 0 disables history" {
echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt"
echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt"
BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 0 3>&-
assert_output "database"
}
@test "BEMOJI_LIMIT_RECENT=0 disables history" {
echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt"
echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt"
BEMOJI_LIMIT_RECENT=0 BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji 3>&-
assert_output "database"
}