├── .gitmodules ├── .woodpecker.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── assets ├── bemenu.png ├── help.png ├── rofi.png └── wofi.png ├── bemoji └── test ├── bemoji_cmds.bats ├── bemoji_directories.bats ├── bemoji_download.bats ├── bemoji_errors.bats ├── bemoji_history.bats └── resources └── test_emoji.txt /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/bats"] 2 | path = test/bats 3 | url = https://github.com/bats-core/bats-core.git 4 | [submodule "test/test_helper/bats-support"] 5 | path = test/test_helper/bats-support 6 | url = https://github.com/bats-core/bats-support.git 7 | [submodule "test/test_helper/bats-assert"] 8 | path = test/test_helper/bats-assert 9 | url = https://github.com/bats-core/bats-assert.git 10 | [submodule "test/test_helper/mocks"] 11 | path = test/test_helper/mocks 12 | url = https://github.com/jasonkarns/bats-mock.git 13 | -------------------------------------------------------------------------------- /.woodpecker.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | test: 3 | image: bats/bats 4 | commands: 5 | - /opt/bats/bin/bats test 6 | 7 | release-prep: 8 | # prepare changelog and version information for release candidate 9 | when: 10 | event: tag 11 | ref: refs/tags/v* 12 | image: alpine 13 | commands: 14 | - sed -ne 's/bm_version=\(.*\)/\1/p' bemoji > NEWEST_VERSION.txt 15 | - awk '/^## \[\d/{p++} p==2{print; exit} p>=1' CHANGELOG.md | head -n -1 | tail -n+3 > NEWEST_CHANGES.txt 16 | 17 | versioncompare: 18 | # ensure we correctly bumped versions 19 | when: 20 | event: tag 21 | ref: refs/tags/v* 22 | image: alpine 23 | secrets: [ github_release_token, github_repo ] 24 | commands: 25 | - apk add jq curl 26 | - "lastversion=$(curl -X GET -H \"Accept: application/vnd.github.v3+json\" -H \"Authorization: Bearer $GITHUB_RELEASE_TOKEN\" https://api.github.com/repos/$GITHUB_REPO/releases/latest | jq -r '.name')" 27 | - "programversion=$(cat NEWEST_VERSION.txt)" 28 | - changelogversion=$(sed -ne 's/^## \[\([0-9].*\)\].*$/\1/p' CHANGELOG.md | head -n1) 29 | - echo "Last version - $lastversion" 30 | - echo "New version - $programversion" 31 | - echo "Changelog version - $changelogversion" 32 | - "if [ \"$changelogversion\" != \"$programversion\" ]; then { echo \"VERSION MISMATCH: Changelog - $changelogversion, Program - $programversion\" && exit 1; }; fi" 33 | - "if [ \"$lastversion\" = \"$programversion\" ]; then { echo \"RELEASE DUPLICATE: Last release already had version - $programversion\" && exit 1; }; fi" 34 | 35 | build: 36 | when: 37 | event: tag 38 | ref: refs/tags/v* 39 | image: savant/md2man 40 | commands: 41 | - apk update && apk add zip 42 | - BM_VERSION=$(cat NEWEST_VERSION.txt) 43 | - mkdir -p build/doc dist 44 | - cp bemoji build 45 | - md2man -in README.md -out bemoji.1 && gzip bemoji.1 46 | - cp LICENSE README.md bemoji.1.gz build/doc 47 | - cd build || exit 1 48 | - tar -czvf bemoji-$BM_VERSION.tar.gz * 49 | - zip -r bemoji-$BM_VERSION.zip * 50 | - mv bemoji-$BM_VERSION.tar.gz bemoji-$BM_VERSION.zip ../dist 51 | 52 | release-gitea: 53 | when: 54 | event: tag 55 | ref: refs/tags/v* 56 | image: plugins/gitea-release 57 | settings: 58 | api_key: 59 | from_secret: gitea_release_token 60 | base_url: https://git.martyoeh.me 61 | files: dist/* 62 | title: NEWEST_VERSION.txt 63 | note: NEWEST_CHANGES.txt 64 | 65 | release-github: 66 | when: 67 | event: tag 68 | ref: refs/tags/v* 69 | image: alpine 70 | secrets: [ github_release_token, github_repo ] 71 | commands: 72 | - apk add file jq curl 73 | - BM_VERSION=$(cat NEWEST_VERSION.txt) 74 | - BM_CHANGED=$(sed -e 's|#||g' -e 's|^.*$|\0
|' NEWEST_CHANGES.txt) # display newlines workaround 75 | - 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 76 | - "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\")" 77 | - "uploadurl=$(echo $response | jq -r '.upload_url' | cut -d'{' -f1)" 78 | - "[ $uploadurl = null ] && { echo $response; exit 1; }" 79 | - "curl -X POST -H \"Accept:\\ application/vnd.github.v3+json\" -H \"Authorization:\\ Bearer $GITHUB_RELEASE_TOKEN\" -H \"Content-Type:\\ $(file -b --mime-type dist/bemoji-$BM_VERSION.zip)\" -H \"Content-Length:\\ $(wc -c 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ## [0.4.0] - 2024-02-22 23 | 24 | ### Added 25 | 26 | - Add default support for `fuzzel` wayland-native picker tool 27 | - Add default support for `ilia` gtk-based picker tool, used by default in Regolith Linux 28 | - Pass through return code 1 from selection tool 29 | - (!) Number of displayed recent emoji can be set with `-P` option: 30 | This replaces previous `-P` history flag toggle. Use number to set amount of recent 31 | entries to display, `-P3`. To completely hide history use `-P0`. 32 | - Add nerdfont emoji set download with `-D nerd` 33 | - Add parsing for long-form options (`--private` instead of `-p` and so on): 34 | Options requiring a value can be given both in space-separated (`--hist-limit 2`) 35 | and equals-separated (`--hist-limit=2`) versions. POSIX option concatenation still 36 | works (`-ne` to echo without newline). 37 | 38 | ### Changed 39 | 40 | - (!) History uses `XDG_STATE_HOME` directory by default: 41 | This constitutes a break in behavior if you relied a lot on your pick history in the default 42 | location. To retain your old history file, simply move it from the old cache directory 43 | (`~/.cache/bemoji-history.txt` by default) to the new one (`~/.local/state/bemoji-history.txt` 44 | by default). 45 | - (!) `XDG_CACHE_LOCATION` renamed to `XDG_HISTORY_LOCATION` to better signify its purpose 46 | 47 | ### Fixed 48 | 49 | - Always download from newest emoji list url 50 | - Pass selection to custom typing tools through stdin 51 | - Pass info messages to stderr to avoid passing to picker tools 52 | 53 | ## [0.3.0] - 2022-11-10 54 | 55 | ### Added 56 | 57 | - Add new option `-n` which suppresses printing the final newline character in output 58 | 59 | ### Changed 60 | 61 | - Multiple command options can be combined 62 | - Allow downloading emoji sets at any time after initial run with `-D ` 63 | 64 | ### Fixed 65 | 66 | - Custom default command is only executed when no command option given 67 | - Results are matched case insensitively when using rofi picker to match other pickers 68 | 69 | ## [0.2.0] - 2022-06-29 70 | 71 | ### Added 72 | 73 | - Display of configuration options on `-v` toggle 74 | - AUR installation instructions 75 | 76 | ### Changed 77 | 78 | - Simplified grep invocation to adhere more closely to POSIX 79 | 80 | ### Fixed 81 | 82 | - Custom picker, clipper, and typer command invocation quoting 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 - 2024 Marty Oehme 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bemoji ❤️ - Quickly ⛏️ your 🌟 2 | 3 | [![status-badge](https://ci.martyoeh.me/api/badges/Marty/bemoji/status.svg)](https://ci.martyoeh.me/Marty/bemoji) 4 | 5 | ![bemoji picker interface on bemenu](assets/bemenu.png) 6 | 7 | Emoji picker with support for bemenu/wofi/rofi/dmenu and wayland/X11. 8 | 9 | Will remember your favorite emojis and give you quick access. 10 | 11 | ## 📁 Installation 12 | 13 | ### Dependencies 14 | 15 | * One of `bemenu`, `wofi`, `rofi`, `dmenu`, `ilia`, `fuzzel` or supplying your own picker. 16 | * One of `wl-copy`, `xclip`, `xsel` or supplying your own clipboard tool. 17 | * One of `wtype`, `xdotool` or supplying your own typing tool. 18 | * `sed`, `grep`, `cut`, `sort`, `uniq`, `tr`, `curl` if using the download functionality. 19 | 20 | To see how to substitute the default choices with your own tools, 21 | see Options below. 22 | 23 | ![rofi picker interface](assets/rofi.png) 24 | 25 | ### Manual 26 | 27 | Option 1. Clone the repository and put the executable somewhere in your path: 28 | 29 | ```sh 30 | git clone 31 | chmod +x bemoji/bemoji 32 | mv bemoji/bemoji /usr/local/bin/bemoji 33 | rm -r bemoji 34 | ``` 35 | 36 | Option 2. Clone the repository and link the executable to your path: 37 | 38 | ```sh 39 | git clone 40 | chmod +x bemoji/bemoji 41 | ln -s bemoji/bemoji /usr/local/bin/bemoji 42 | ``` 43 | 44 | ### Arch Linux 45 | 46 | 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.: 47 | 48 | ```sh 49 | paru -S bemoji # or bemoji-git 50 | ``` 51 | 52 | ## 💿 Usage 53 | 54 | ![wofi picker interface](assets/wofi.png) 55 | 56 | Simply execute `bemoji` without any options to set up the default emoji database and let you quickly pick an emoji. 57 | It will be copied to your clipboard for you to paste anywhere. 58 | If you execute `bemoji -t` it will directly type your emoji directly into whatever application is in focus. 59 | 60 | 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, 61 | regardless of what the default action is set to. 62 | (Currently works in bemenu and rofi.) 63 | 64 | You can also map the picker to a key combination for quick access, e.g. 65 | 66 | In `swaywm`, put the following in `~/.config/sway/config`: 67 | 68 | ``` 69 | bindsym Mod4+Shift+e exec bemoji -t 70 | ``` 71 | 72 | For `i3`, put the same into `~/.config/i3/config`: 73 | 74 | ``` 75 | bindsym Mod4+Shift+e exec bemoji -t 76 | ``` 77 | 78 | For `riverwm`, put the following in `~/.config/river/init`: 79 | 80 | ``` 81 | riverctl map normal Mod4+Shift E spawn "bemoji -t" 82 | ``` 83 | 84 | In `sxhkd`, put the following into `~/.config/sxhkd/sxhkdrc`: 85 | 86 | ``` 87 | super + Shift + e 88 | bemoji -t 89 | ``` 90 | 91 | And you can easily type any emoji with the help of `Super+Shift+E`. 92 | 93 | ## 🧰 Options 94 | 95 | ![bemoji help window](assets/help.png) 96 | 97 | bemoji comes with a couple of options to specify actions, emoji libraries and directories being used. 98 | 99 | ### Adding your own emoji 100 | 101 | Simply put your own emoji list into the bemoji data directory. 102 | By default, the directory will be at your `$XDG_DATA_HOME/bemoji` location - 103 | most likely this is `~/.local/share/bemoji`. 104 | 105 | Add any number of `.txt` files containing additional emoji to this directory: 106 | 107 | ``` 108 | 🫦 Biting lip 109 | 🫶 Heart Hands 110 | ``` 111 | 112 | The lists *need* to have the format `🙂 description of emoji` with a whitespace separating the emoji and its description. 113 | The description can have as many words and whitespaces as you want. 114 | 115 | ### Ignoring the most recent emoji 116 | 117 | By default, bemoji will sort the list it displays by your most frequently and most recently used emoji. 118 | To disable this behavior, execute bemoji like the following: 119 | 120 | ```sh 121 | bemoji --hist-limit 0 122 | ``` 123 | 124 | This will stop bemoji from adding recently used emoji before displaying the list. 125 | 126 | You can also stop bemoji from adding any emoji to your history in the first place: 127 | 128 | ```sh 129 | bemoji --private 130 | ``` 131 | 132 | This will not add any of the emoji you pick to your recent emojis. 133 | Put both together to completely ignore the recent emoji feature of the program 134 | (these are the equivalent short versions of the options above): 135 | 136 | ```sh 137 | bemoji -p -P0 138 | ``` 139 | 140 | Like this, you'll be hiding any recent personal emoji and keep any new ones you use out of your history. 141 | 142 | 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. 143 | For example, to display only the top 4 recently used emoji: 144 | 145 | ```sh 146 | bemoji --hist-limit 4 147 | ``` 148 | 149 | The recent list will also contain emoji that are *not* usually on your lists, 150 | so kept in single-use lists for example. 151 | If you don't wish those to show up, make use of these options. 152 | 153 | ### Setting custom directories and editing history 154 | 155 | By default bemoji stores your recent history in `$XDG_STATE_HOME/bemoji-history.txt`, 156 | so most often in `~/.local/state/bemoji-history.txt` 157 | 158 | You can edit this file in any text editor to change your recent history, 159 | removing, adding or changing the emoji appearing there. 160 | 161 | You can overwrite the directories bemoji uses for its emoji lists and history files with the following two environment variables: 162 | 163 | ```sh 164 | BEMOJI_DB_LOCATION=/path/to/my/emoji/directory 165 | BEMOJI_HISTORY_LOCATION=/path/to/my/state/directory 166 | ``` 167 | 168 | There are no equivalent commandline arguments to overwrite these two settings. 169 | 170 | ### Display one custom emoji list 171 | 172 | A custom emoji list can be supplied as commandline argument `-f` or `BEMOJI_CUSTOM_LIST` environment variable. 173 | 174 | ```sh 175 | bemoji --file path/to/my/list.txt 176 | ``` 177 | 178 | The list will override the normally presented emoji, 179 | so that only the custom list and recent emoji will be displayed. 180 | To display *only* the emoji list passed in, pass an extra `-P` flag to bemoji. 181 | 182 | The path can also be a weblink which bemoji will download and use: 183 | 184 | ```sh 185 | bemoji -f "https://raw.githubusercontent.com/jchook/emoji-menu/master/data/emojis.txt" 186 | ``` 187 | 188 | ### Download additional emoji sets 189 | 190 | bemoji automatically downloads an emoji list for you to use on first invocation. 191 | By default, it only downloads emoji, though you can have it download math symbols and nerdfont icons as well. 192 | To download additional sets, execute bemoji like the following: 193 | 194 | ```sh 195 | bemoji --download all 196 | ``` 197 | 198 | 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. 199 | Other valid options for this setting are `emoji`, `math`, `nerd`, `none`. 200 | 201 | ```sh 202 | bemoji -D "math emoji nerd" 203 | ``` 204 | 205 | The above command is equivalent to the previous `all` as you can mention multiple sets you want downloaded. 206 | 207 | If set to `none` and no files are in the emoji directory, 208 | bemoji will complain and not show anything. 209 | 210 | ### Do not skip to new line after output 211 | 212 | By default, bemoji will craft the final output using a typical `echo` call for anything it prints directly. 213 | 214 | That means, it will also contain a final newline character. 215 | So, for example it would technically output `🦊\n` for the `fox` emoji, 216 | which skips to a new line in most circumstances. 217 | 218 | If you wish to prevent this character in the final output, use: 219 | 220 | ```sh 221 | bemoji -n 222 | ``` 223 | 224 | Using this option will suppress the newline character and *only* print `🦊` as its output. 225 | 226 | ### Using a custom tool for picking, clipping, typing 227 | 228 | If you want to replace one of the default supported tools with your own you can do this through environment variables: 229 | 230 | ```sh 231 | BEMOJI_PICKER_CMD="path/to/your/picker-tool" 232 | BEMOJI_CLIP_CMD="path/to/your/clipboard/tool" 233 | BEMOJI_TYPE_CMD="path/to/your/xdotool" 234 | ``` 235 | 236 | The candidate list (in the case of picker tool) or the picked selection are passed to the tools through stdin. 237 | 238 | For example, to manually invoke fuzzel with no extra options as the picker for bemoji you would use: 239 | 240 | ```sh 241 | BEMOJI_PICKER_CMD="fuzzel -d" bemoji 242 | ``` 243 | 244 | This is somewhat experimental still and you'll have to see how well it works for you. 245 | The setting can not be changed through the commandline alone. 246 | 247 | ### Execute a custom command with my emoji 248 | 249 | You can execute bemoji with the `-e` flag with which you tell it not to do anything but echo out the chosen emoji. 250 | 251 | This can be very useful for creating your own little script with it: 252 | 253 | ```bash 254 | bemoji --echo | cat <(echo -n "https://emojipedia.org/") - | xargs xdg-open 255 | ``` 256 | 257 | This snippet will open a wiki page for the picked emoji in your browser. 258 | 259 | Of course, there are many more possibilities. 260 | This is just an example to show how the echo mode works. 261 | 262 | ### A list of all environment variables 263 | 264 | What follows is a list of all environment variables bemoji understands, 265 | with their default settings 266 | 267 | | Description | Commandline option | env | default | 268 | | --- | --- | --- | --- | 269 | | enable/disable newline | -n, --noline | BEMOJI_ECHO_NEWLINE | true | 270 | | enable private mode | -p,--private | BEMOJI_PRIVATE_MODE | false | 271 | | limit history items | -P,--hist-limit | BEMOJI_LIMIT_RECENT | | 272 | | download specific emoji lists | -D,--download | BEMOJI_DOWNLOAD_LIST | | 273 | | read emoji from file | -f,--file | BEMOJI_CUSTOM_LIST | | 274 | | emoji lists directory | | BEMOJI_DB_LOCATION | $XDG_DATA_HOME/bemoji | 275 | | emoji history directory | | BEMOJI_HISTORY_LOCATION | $XDG_STATE_HOME | 276 | | custom default command | | BEMOJI_DEFAULT_CMD | | 277 | | custom type command | | BEMOJI_TYPE_CMD | | 278 | | custom pick command | | BEMOJI_PICKER_CMD | | 279 | | custom clip command | | BEMOJI_CLIP_CMD | | 280 | 281 | The environment variables have the following effects: 282 | 283 | ```sh 284 | BEMOJI_DB_LOCATION="$XDG_DATA_HOME/bemoji" # where the emoji lists reside 285 | BEMOJI_HISTORY_LOCATION="$XDG_STATE_HOME" # where the state file resides 286 | BEMOJI_CUSTOM_LIST="" # the custom emoji list to display 287 | BEMOJI_DOWNLOAD_LIST="" # the default emoji lists to download to database 288 | BEMOJI_DEFAULT_COMMAND="" # which command to invoke by default 289 | BEMOJI_PICKER_CMD="bemenu" # which picker tool to use 290 | BEMOJI_CLIP_CMD="wl-copy" # which clipboard tool to use 291 | BEMOJI_TYPE_CMD="wtype" # which typing tool to use (ydotool will NOT work) 292 | BEMOJI_PRIVATE_MODE=false # whether to save new entries 293 | BEMOJI_LIMIT_RECENT="" # whether to display recent entries 294 | BEMOJI_ECHO_NEWLINE=true # whether to end the output with a newline character 295 | ``` 296 | 297 | They can either be set like `export BEMOJI_LIMIT_RECENT=5` before executing `bemoji` and will 298 | remain in the shell environment. 299 | Or they can be set for just a single run of `bemoji` like this: 300 | 301 | ```sh 302 | BEMOJI_ECHO_NEWLINE=true BEMOJI_PRIVATE_MODE=true bemoji 303 | ``` 304 | 305 | This is especially useful for advanced configurations like custom commands which do not have an 306 | equivalent option to be set. Be careful with setting environment variables as setting them wrong 307 | or forgetting about them can have detrimental impacts on the functionality of this program! 308 | 309 | ## 🤗 Issues 310 | 311 | Thanks for checking this program out! ❤ 312 | 313 | If there are any problems, don't hesitate to open an issue. 314 | 315 | If you have an idea or improvement, don't hesitate to open a merge request! 316 | 317 | ### Known issues 318 | 319 | There is a known issue concerning some GUI application which do not receive the correct emojis 320 | when auto-typing and instead a bunch of empty unicode squares. 321 | It seems to be an issue with `wtype` and may need to be fixed upstream. 322 | 323 | Unfortunately, `wtype` is the only stable wayland typing backend to my current knowledge. 324 | Until `bemoji` supports more typing backends on wayland, a workaround seems to be to save the 325 | emoji to the clipboard and have a typing tool paste the contents of the clipboard directly, 326 | like the following: 327 | 328 | ```sh 329 | bemoji -cn && echo key ctrl+v | dotool 330 | ``` 331 | 332 | The issue is tracked at [#34](https://github.com/marty-oehme/bemoji/issues/34). 333 | 334 | ### Running tests 335 | 336 | This project makes use of [bash-bats](https://github.com/bats-core/bats-core) (community fork) to test some of its functionality. 337 | 338 | To run the tests locally: 339 | 340 | ```sh 341 | git submodule init 342 | git submodule update 343 | ./test/bats/bin/bats test 344 | ``` 345 | 346 | 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. 347 | 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. 348 | -------------------------------------------------------------------------------- /assets/bemenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-oehme/bemoji/1b5e9c1284ede59d771bfd43780cc8f6f7446f38/assets/bemenu.png -------------------------------------------------------------------------------- /assets/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-oehme/bemoji/1b5e9c1284ede59d771bfd43780cc8f6f7446f38/assets/help.png -------------------------------------------------------------------------------- /assets/rofi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-oehme/bemoji/1b5e9c1284ede59d771bfd43780cc8f6f7446f38/assets/rofi.png -------------------------------------------------------------------------------- /assets/wofi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marty-oehme/bemoji/1b5e9c1284ede59d771bfd43780cc8f6f7446f38/assets/wofi.png -------------------------------------------------------------------------------- /bemoji: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | bm_version=0.4.0 4 | # Emoji default database location 5 | bm_db_location=${BEMOJI_DB_LOCATION:-"${XDG_DATA_HOME:-$HOME/.local/share}/bemoji"} 6 | # Setting custom emoji list file location: 7 | # BEMOJI_CUSTOM_LIST=/my/location/emojis.txt 8 | # Setting custom recent emoji history: 9 | # BEMOJI_HISTORY_LOCATION=/path/to/my/recents/directory 10 | bm_state_dir="${BEMOJI_HISTORY_LOCATION:-${XDG_STATE_HOME:-$HOME/.local/state}}" 11 | bm_history_file="${bm_state_dir}/bemoji-history.txt" 12 | 13 | # Command to run after user chooses an emoji 14 | bm_default_cmd="$BEMOJI_DEFAULT_CMD" 15 | 16 | # Newline after echo 17 | bm_echo_newline=${BEMOJI_ECHO_NEWLINE:-true} 18 | # Do not save choices 19 | bm_private_mode=${BEMOJI_PRIVATE_MODE:-false} 20 | # Do not sort results 21 | bm_limit_recent="$BEMOJI_LIMIT_RECENT" 22 | 23 | declare -A default_pickers=( 24 | ["bemenu"]="bemenu -p 🔍 -i -l 20" 25 | ["wofi"]="wofi -p 🔍 -i --show dmenu" 26 | ["rofi"]="rofi -p 🔍 -i -dmenu --kb-custom-1 "Alt+1" --kb-custom-2 "Alt+2"" 27 | ["dmenu"]="dmenu -p 🔍 -i -l 20" 28 | ["wmenu"]="wmenu -p 🔍 -i -l 20" 29 | ["ilia"]="ilia -n -p textlist -l 'Emoji' -i desktop-magnifier" 30 | ["fuzzel"]="fuzzel -d -p '🔍 '" 31 | ) 32 | 33 | # Report usage 34 | usage() { 35 | echo "Usage: $(basename "$0") [-t | -c | -e] [-f ] [-p] [-P] [-D ]" 1>&2 36 | echo 37 | echo "A simple emoji picker. Runs on bemenu/wofi/rofi/dmenu by default." 38 | echo "Invoked without arguments sends the picked emoji to the clipboard." 39 | echo 40 | echo " Command options (can be combined):" 41 | echo " -t, --type Simulate typing the emoji choice with the keyboard." 42 | echo " -c, --clip Send emoji choice to the clipboard. (default)" 43 | echo " -e, --echo Only echo out the picked emoji." 44 | echo "" 45 | echo " Other options:" 46 | echo " -n, --noline Do not print a newline after the picked emoji." 47 | echo " -p, --private Do not save picked emoji to recent history." 48 | echo " -P, --hist-limit Limit number of recent emoji to display." 49 | echo " -D, --download Choose from default lists to download." 50 | echo " Valid choices: all|none|emoji|math|nerd (multiple choices possible)." 51 | echo " -f, --file Use a custom emoji database. Can be a url which will be retrieved." 52 | echo " -v, --version Display current program version and directory configuration." 53 | echo " -h, --help Show this help." 54 | echo 55 | exit "$1" 56 | } 57 | 58 | version() { 59 | printf "v%s\ndatabase=%s\nhistory=%s\n" "$bm_version" "$bm_db_location" "$bm_history_file" 60 | exit 61 | } 62 | 63 | msg() { 64 | # Outputs a message to stderr, to be used for info, warning and error messages. 65 | printf "%s\n" "$1" >&2 66 | } 67 | 68 | parse_cli() { 69 | while getopts cD:ef:hnpP:tv-: arg "$@"; do 70 | case "$arg" in 71 | c) bm_cmds+=(_clipper) ;; 72 | D) _opt_set_download_list "${OPTARG}" ;; 73 | e) bm_cmds+=(cat) ;; 74 | f) _opt_set_custom_list "${OPTARG}" ;; 75 | h) usage 0 ;; 76 | n) bm_echo_newline=false ;; 77 | p) bm_private_mode=true ;; 78 | P) _opt_set_hist_limit "${OPTARG}" ;; 79 | t) bm_cmds+=(_typer) ;; 80 | v) version ;; 81 | -) 82 | LONG_OPTARG="${OPTARG#*=}" 83 | case "$OPTARG" in 84 | clip) bm_cmds+=(_clipper) ;; 85 | download=?*) _opt_set_download_list "${LONG_OPTARG}" ;; 86 | download*) 87 | _opt_set_download_list "${*:$OPTIND:1}" 88 | OPTIND=$((OPTIND + 1)) 89 | ;; 90 | echo) bm_cmds+=(cat) ;; 91 | file=?*) _opt_set_custom_list "${LONG_OPTARG}" ;; 92 | file*) 93 | _opt_set_custom_list "${*:$OPTIND:1}" 94 | OPTIND=$((OPTIND + 1)) 95 | ;; 96 | help) usage 0 ;; 97 | noline) bm_echo_newline=false ;; 98 | private) bm_private_mode=true ;; 99 | hist-limit=?*) _opt_set_hist_limit "${LONG_OPTARG}" ;; 100 | hist-limit*) 101 | _opt_set_hist_limit "${*:$OPTIND:1}" 102 | OPTIND=$((OPTIND + 1)) 103 | ;; 104 | type) bm_cmds+=(_typer) ;; 105 | version) version ;; 106 | '') break ;; 107 | *) 108 | echo "Unknown option: ${OPTARG}" 1>&2 109 | usage 1 110 | ;; 111 | esac 112 | ;; 113 | \?) exit 2 ;; 114 | esac 115 | done 116 | shift $((OPTIND - 1)) 117 | OPTIND=1 118 | } 119 | 120 | _opt_set_custom_list() { 121 | BEMOJI_CUSTOM_LIST="$1" 122 | } 123 | _opt_set_download_list() { 124 | BEMOJI_DOWNLOAD_LIST="$1" 125 | } 126 | _opt_set_hist_limit() { 127 | bm_limit_recent="$1" 128 | } 129 | 130 | prepare_db() { 131 | # Create list directory 132 | if [ ! -d "$bm_db_location" ]; then 133 | mkdir -p "$bm_db_location" 134 | fi 135 | 136 | if [ -n "$BEMOJI_DOWNLOAD_LIST" ]; then 137 | # Populate default lists 138 | if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'none'; then 139 | msg "Not downloading a default emoji list." 140 | return 141 | elif echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'all'; then 142 | dl_default_emoji 143 | dl_math_symbols 144 | dl_nerd_symbols 145 | return 146 | else 147 | if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'emoji'; then 148 | dl_default_emoji 149 | fi 150 | if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'math'; then 151 | dl_math_symbols 152 | fi 153 | if echo "$BEMOJI_DOWNLOAD_LIST" | grep -q -e 'nerd'; then 154 | dl_nerd_symbols 155 | fi 156 | fi 157 | fi 158 | if [ -n "$(find "$bm_db_location" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then 159 | dl_default_emoji 160 | fi 161 | } 162 | 163 | dl_default_emoji() { 164 | local emojis 165 | emojis=$(curl -sSL "https://unicode.org/Public/emoji/latest/emoji-test.txt") 166 | printf "%s" "$emojis" | sed -ne 's/^.*; fully-qualified.*# \(\S*\) \S* \(.*$\)/\1 \2/gp' >"$bm_db_location/emojis.txt" 167 | msg "Downloaded default emoji set." 168 | } 169 | dl_math_symbols() { 170 | curl -sSL "https://unicode.org/Public/math/latest/MathClassEx-15.txt" | 171 | grep -ve '^#' | cut -d';' -f3,7 | sed -e 's/;/ /' >"$bm_db_location/math.txt" 172 | msg "Downloaded math symbols set." 173 | } 174 | dl_nerd_symbols() { 175 | local nerd all 176 | nerd=$(curl -sSL "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css") 177 | all+=$(printf "%s" "$nerd" | sed -ne '/\.nf-/p' -e '/\s*[^_]content:/p' | sed -e 'N;s/^\.nf-\(.*\):before.* content: \"\\\(.*\)\";/\\U\2 \1/') 178 | echo -e "$all" >"$bm_db_location/nerdfont.txt" 179 | msg "Downloaded nerdfont symbols set." 180 | } 181 | 182 | gather_emojis() { 183 | local result 184 | if [ -n "$BEMOJI_CUSTOM_LIST" ] && [ -f "$BEMOJI_CUSTOM_LIST" ]; then 185 | result=$(cat "$BEMOJI_CUSTOM_LIST") 186 | elif [ -n "$BEMOJI_CUSTOM_LIST" ] && curl -fsSI "$BEMOJI_CUSTOM_LIST" >/dev/null 2>&1; then 187 | result=$(curl -sSL "$BEMOJI_CUSTOM_LIST") 188 | else 189 | result=$(cat "$bm_db_location"/*.txt) 190 | fi 191 | 192 | if [ -n "$bm_limit_recent" ] && [ "$bm_limit_recent" -eq 0 ]; then 193 | printf "%s" "$result" 194 | return 195 | fi 196 | 197 | printf "%s\n%s" "$(get_most_recent "$bm_limit_recent")" "$result" | cat -n - | sort -uk2 | sort -n | cut -f2- 198 | } 199 | 200 | get_most_recent() { 201 | local limit=${1} 202 | local recent_file="$bm_history_file" 203 | if [ ! -f "$recent_file" ]; then 204 | touch "$recent_file" 205 | fi 206 | # TODO: improve this messy line 207 | local result 208 | result=$(sed -e '/^$/d' "$recent_file" | 209 | sort | 210 | uniq -c | 211 | sort -k1rn | 212 | sed -e 's/^\s*//' | 213 | cut -d' ' -f2-) 214 | if [ -z "$limit" ]; then 215 | echo "$result" 216 | else 217 | echo "$result" | head -n "$limit" 218 | fi 219 | } 220 | 221 | add_to_recent() { 222 | if [ -z "$1" ]; then return; fi 223 | if [ ! -d "$bm_state_dir" ]; then 224 | mkdir -p "$bm_state_dir" 225 | fi 226 | echo "$1" >>"$bm_history_file" 227 | } 228 | 229 | # Set default clipboard util 230 | _clipper() { 231 | if [ -n "$BEMOJI_CLIP_CMD" ]; then 232 | # shellcheck disable=SC2068 233 | ${BEMOJI_CLIP_CMD[@]} 234 | elif [ -n "$WAYLAND_DISPLAY" ] && command -v wl-copy >/dev/null 2>&1; then 235 | wl-copy 236 | elif [ -n "$DISPLAY" ] && command -v xclip >/dev/null 2>&1; then 237 | xclip -selection clipboard 238 | elif [ -n "$DISPLAY" ] && command -v xsel >/dev/null 2>&1; then 239 | xsel -b 240 | else 241 | msg "No suitable clipboard tool found." 242 | exit 1 243 | fi 244 | } 245 | 246 | # Set default typing util 247 | _typer() { 248 | local totype 249 | totype=$(cat -) 250 | 251 | if [ -n "$BEMOJI_TYPE_CMD" ]; then 252 | # shellcheck disable=SC2068 253 | ${BEMOJI_TYPE_CMD[@]} "$totype" 254 | return 255 | fi 256 | 257 | if [ -n "$WAYLAND_DISPLAY" ] && command -v wtype >/dev/null 2>&1; then 258 | wtype -s 30 "$totype" 259 | elif [ -n "$DISPLAY" ] && command -v xdotool >/dev/null 2>&1; then 260 | xdotool type --delay 30 "$totype" 261 | else 262 | msg "No suitable typing tool found." 263 | exit 1 264 | fi 265 | } 266 | 267 | # Set default picker util 268 | _picker() { 269 | if [ -n "$BEMOJI_PICKER_CMD" ]; then 270 | eval "${BEMOJI_PICKER_CMD[*]}" 271 | return 272 | fi 273 | 274 | for tool in "${!default_pickers[@]}"; do 275 | if command -v "$tool" >/dev/null 2>&1; then 276 | eval "${default_pickers[$tool]}" 277 | return 278 | fi 279 | done 280 | 281 | msg "No suitable picker tool found." 282 | exit 1 283 | } 284 | 285 | parse_cli "$@" 286 | 287 | [ -n "$BEMOJI_CUSTOM_LIST" ] || prepare_db 288 | result=$(gather_emojis | _picker) 289 | exit_value="$?" 290 | [ "$bm_private_mode" = true ] || add_to_recent "$result" 291 | result=$(echo "$result" | grep -o '^\S\+' | tr -d '\n') 292 | 293 | printout() { # $1=emoji 294 | if [ "$bm_echo_newline" = true ]; then 295 | printf "%s\n" "$*" 296 | else 297 | printf "%s" "$*" 298 | fi 299 | } 300 | 301 | case "$exit_value" in 302 | 1) 303 | exit 1 304 | ;; 305 | 0) 306 | if [ ${#bm_cmds[@]} -eq 0 ]; then 307 | if [ -n "$bm_default_cmd" ]; then 308 | # shellcheck disable=SC2068 309 | printout "$result" | ${bm_default_cmd[@]} 310 | exit 311 | fi 312 | bm_cmds+=(_clipper) 313 | fi 314 | for cmd in "${bm_cmds[@]}"; do 315 | printout "$result" | "$cmd" 316 | done 317 | ;; 318 | 10) 319 | printout "$result" | _clipper 320 | ;; 321 | 11) 322 | printout "$result" | _typer 323 | ;; 324 | esac 325 | exit 326 | -------------------------------------------------------------------------------- /test/bemoji_cmds.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | setup_file() { 4 | # make bemoji executable from anywhere relative to current testfile 5 | TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$TEST_DIR/..:$PATH" 7 | } 8 | 9 | setup() { 10 | load 'test_helper/bats-support/load' 11 | load 'test_helper/bats-assert/load' 12 | 13 | # mock out interactive picker for static emoji return 14 | export BEMOJI_PICKER_CMD="echo ❤️" 15 | 16 | # set up small default set of test emoji for each test 17 | export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database" 18 | export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history" 19 | mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION" 20 | cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt" 21 | } 22 | 23 | @test "-v prints correct version number" { 24 | the_version=$(grep 'bm_version=' "$(which bemoji)") 25 | 26 | run bemoji -v 27 | assert_output --partial "v${the_version#bm_version=}" 28 | } 29 | 30 | @test "Runs clipping command by default" { 31 | BEMOJI_CLIP_CMD="echo clipping default" run bemoji 3>&- 32 | assert_output "clipping default" 33 | } 34 | 35 | @test "Runs echo command on -e option" { 36 | run bemoji -e 3>&- 37 | assert_output "❤️" 38 | } 39 | 40 | @test "Runs clipping command on -c option" { 41 | BEMOJI_CLIP_CMD="echo clipping result" run bemoji -c 3>&- 42 | assert_output "clipping result" 43 | } 44 | 45 | @test "Runs typing command on -t option" { 46 | BEMOJI_TYPE_CMD="echo typing result" run bemoji -t 3>&- 47 | assert_output "typing result" 48 | } 49 | 50 | @test "Runs typing and clipping on -ct options" { 51 | BEMOJI_CLIP_CMD="echo clipping result" BEMOJI_TYPE_CMD="echo typing result" run bemoji -ct 3>&- 52 | assert_output \ 53 | "clipping result 54 | typing result" 55 | } 56 | 57 | @test "Passes selection to custom typer tool through stdin" { 58 | BEMOJI_TYPE_CMD="cat -" run bemoji -t 3>&- 59 | assert_output "❤️" 60 | } 61 | 62 | @test "Runs custom default command" { 63 | BEMOJI_DEFAULT_CMD="echo my custom command" run bemoji 3>&- 64 | assert_output "my custom command" 65 | } 66 | 67 | @test "Using command option overrides custom default command" { 68 | BEMOJI_DEFAULT_CMD="echo my custom command" BEMOJI_CLIP_CMD="echo my clipping" run bemoji -c 3>&- 69 | assert_output "my clipping" 70 | } 71 | 72 | @test "Returns status code 1 on picker status code 1" { 73 | BEMOJI_PICKER_CMD="return 1" run bemoji -e 3>&- 74 | assert_failure 1 75 | } 76 | 77 | @test "Prints output with newline by default" { 78 | bats_require_minimum_version 1.5.0 79 | BEMOJI_PICKER_CMD="echo heart" run --keep-empty-lines -- bemoji -e 80 | assert_output --regexp '^heart\n$' 81 | } 82 | 83 | @test "Prints output without newline on -n option" { 84 | bats_require_minimum_version 1.5.0 85 | BEMOJI_PICKER_CMD="echo heart" run --keep-empty-lines -- bemoji -ne 86 | assert_output --regexp '^heart$' 87 | } 88 | 89 | @test "Understands long-form options" { 90 | run bemoji --help 91 | assert_success 92 | assert_output --partial "A simple emoji picker." 93 | } 94 | 95 | @test "Understands long-form equals values" { 96 | BEMOJI_CLIP_CMD="echo heart" run bemoji --hist-limit=0 97 | assert_success 98 | } 99 | 100 | @test "Understands long-form spaced values" { 101 | BEMOJI_CLIP_CMD="echo heart" run bemoji --hist-limit 0 102 | assert_success 103 | } 104 | 105 | @test "Understands short-form spaced values" { 106 | BEMOJI_CLIP_CMD="echo heart" run bemoji -P 0 107 | assert_success 108 | } 109 | 110 | @test "Can concatenate short-form options and values" { 111 | BEMOJI_CLIP_CMD="echo heart" run bemoji -neP0 112 | assert_success 113 | } 114 | -------------------------------------------------------------------------------- /test/bemoji_directories.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | setup_file() { 4 | # make bemoji executable from anywhere relative to current testfile 5 | TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$TEST_DIR/..:$PATH" 7 | } 8 | 9 | setup() { 10 | load 'test_helper/bats-support/load' 11 | load 'test_helper/bats-assert/load' 12 | 13 | # mock out interactive picker for static emoji return 14 | export BEMOJI_PICKER_CMD="echo ❤️" 15 | 16 | # set up small default set of test emoji for each test 17 | export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database" 18 | export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history" 19 | mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION" 20 | cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt" 21 | } 22 | 23 | @test "can run script" { 24 | export BEMOJI_CLIP_CMD="echo clip test only" 25 | # closing FD3 manually to prevent hangs, see 26 | # https://bats-core.readthedocs.io/en/stable/writing-tests.html#file-descriptor-3-read-this-if-bats-hangs 27 | run bemoji 3>&- 28 | assert_success 29 | } 30 | 31 | @test "sets XDG directory for db by default" { 32 | unset BEMOJI_DB_LOCATION 33 | export XDG_DATA_HOME="$BATS_TEST_TMPDIR/xdb-db" 34 | run bemoji -v 35 | assert_output --regexp " 36 | database=$BATS_TEST_TMPDIR/xdb-db/bemoji 37 | " 38 | } 39 | 40 | @test "sets XDG directory for history by default" { 41 | unset BEMOJI_HISTORY_LOCATION 42 | export XDG_STATE_HOME="$BATS_TEST_TMPDIR/xdb-cache" 43 | run bemoji -v 44 | assert_output --regexp " 45 | history=$BATS_TEST_TMPDIR/xdb-cache/bemoji-history.txt$" 46 | } 47 | 48 | @test "falls back to default db directory if no XDG found" { 49 | unset BEMOJI_DB_LOCATION 50 | run bemoji -v 51 | assert_output --regexp " 52 | database=$HOME/.local/share/bemoji 53 | " 54 | } 55 | 56 | @test "falls back to default history location if no XDG found" { 57 | unset BEMOJI_HISTORY_LOCATION 58 | run bemoji -v 59 | assert_output --regexp " 60 | history=$HOME/.local/state/bemoji-history.txt$" 61 | } 62 | 63 | @test "BEMOJI_DB_LOCATION sets correct db directory" { 64 | run bemoji -v 65 | assert_output --regexp " 66 | database=$BATS_TEST_TMPDIR/database 67 | " 68 | } 69 | 70 | @test "BEMOJI_HISTORY_LOCATION sets correct history directory" { 71 | run bemoji -v 72 | assert_output --regexp " 73 | history=$BATS_TEST_TMPDIR/history/bemoji-history.txt$" 74 | } 75 | -------------------------------------------------------------------------------- /test/bemoji_download.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | setup_file() { 4 | # make bemoji executable from anywhere relative to current testfile 5 | TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$TEST_DIR/..:$PATH" 7 | } 8 | 9 | setup() { 10 | load 'test_helper/bats-support/load' 11 | load 'test_helper/bats-assert/load' 12 | load 'test_helper/mocks/stub' 13 | 14 | # mock out interactive picker for static emoji return 15 | export BEMOJI_PICKER_CMD="echo heart" 16 | 17 | # set up small default set of test emoji for each test 18 | export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database" 19 | export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history" 20 | mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION" 21 | } 22 | 23 | @test "Runs emoji download on -D emoji option" { 24 | stub curl \ 25 | "echo -e '1F605 ; fully-qualified # emoji E0.6 grinning face with sweat\nnot picked up\n1F605 ; fully-qualified # emoji2 E0.6 picked up'" 26 | run bemoji -D emojis 3>&- 27 | outcome=$(cat "$BEMOJI_DB_LOCATION/emojis.txt") 28 | assert_equal "$outcome" "emoji grinning face with sweat 29 | emoji2 picked up" 30 | unstub curl 31 | } 32 | 33 | @test "Runs maths download on -D maths option" { 34 | stub curl \ 35 | "echo '03A3;A;Σ;Sigma;ISOGRK3;;GREEK CAPITAL LETTER SIGMA'" 36 | run bemoji -D math 3>&- 37 | outcome=$(cat "$BEMOJI_DB_LOCATION/math.txt") 38 | assert_equal "$outcome" "Σ GREEK CAPITAL LETTER SIGMA" 39 | unstub curl 40 | } 41 | @test "Runs nerdfont download on -D nerd option" { 42 | stub curl \ 43 | "printf 'meangingless\nafiller lines\n.nf-md-pipe_wrench:before { \n content: \"\\\f1354\";\n }'" 44 | run bemoji -D nerd 3>&- 45 | outcome=$(cat "$BEMOJI_DB_LOCATION/nerdfont.txt") 46 | assert_equal "$outcome" "󱍔 md-pipe_wrench" 47 | unstub curl 48 | } 49 | -------------------------------------------------------------------------------- /test/bemoji_errors.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | setup_file() { 4 | # make bemoji executable from anywhere relative to current testfile 5 | TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$TEST_DIR/..:$PATH" 7 | } 8 | 9 | setup() { 10 | load 'test_helper/bats-support/load' 11 | load 'test_helper/bats-assert/load' 12 | 13 | # set up small default set of test emoji for each test 14 | export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database" 15 | export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history" 16 | mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION" 17 | cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt" 18 | 19 | # these tests require stdout to be separated from stderr 20 | # such run flags were only introduced in recent bats version 21 | bats_require_minimum_version 1.5.0 22 | } 23 | 24 | @test "Prints clipper error to stderr" { 25 | BEMOJI_PICKER_CMD="echo hi" run --separate-stderr bemoji 3>&- 26 | assert_output "" 27 | output="$stderr" 28 | assert_output "No suitable clipboard tool found." 29 | } 30 | 31 | @test "Prints picker error to stderr" { 32 | run --separate-stderr bemoji 3>&- 33 | assert_output "" 34 | output="$stderr" 35 | assert_output "No suitable picker tool found." 36 | } 37 | 38 | @test "Prints typer error to stderr" { 39 | BEMOJI_PICKER_CMD="echo hi" run --separate-stderr bemoji -t 3>&- 40 | assert_output "" 41 | output="$stderr" 42 | assert_output "No suitable typing tool found." 43 | } 44 | -------------------------------------------------------------------------------- /test/bemoji_history.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | setup_file() { 4 | # make bemoji executable from anywhere relative to current testfile 5 | TEST_DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" 6 | PATH="$TEST_DIR/..:$PATH" 7 | } 8 | 9 | setup() { 10 | load 'test_helper/bats-support/load' 11 | load 'test_helper/bats-assert/load' 12 | 13 | # mock out interactive picker for static emoji return 14 | export BEMOJI_PICKER_CMD="echo ❤️" 15 | 16 | # set up small default set of test emoji for each test 17 | export BEMOJI_DB_LOCATION="$BATS_TEST_TMPDIR/database" 18 | export BEMOJI_HISTORY_LOCATION="$BATS_TEST_TMPDIR/history" 19 | mkdir -p "$BEMOJI_DB_LOCATION" "$BEMOJI_HISTORY_LOCATION" 20 | cat "$BATS_TEST_DIRNAME/resources/test_emoji.txt" > "$BEMOJI_DB_LOCATION/emoji.txt" 21 | } 22 | 23 | @test "sorts by frecency" { 24 | echo -e "there\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt" 25 | echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt" 26 | BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji 3>&- 27 | assert_output "hellotheredatabase" 28 | } 29 | 30 | @test "history limiting uses sorted results" { 31 | echo -e "zany\nmy\nisee\nonomatopeia" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt" 32 | echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt" 33 | BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 1 3>&- 34 | assert_output "iseedatabase" 35 | } 36 | 37 | @test "history limiting takes frecency into account" { 38 | echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt" 39 | echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt" 40 | BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 1 3>&- 41 | assert_output "hellodatabase" 42 | } 43 | 44 | @test "-P 0 disables history" { 45 | echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt" 46 | echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt" 47 | BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji -P 0 3>&- 48 | assert_output "database" 49 | } 50 | 51 | @test "BEMOJI_LIMIT_RECENT=0 disables history" { 52 | echo -e "there\nfriend\nhello\nhello" > "$BEMOJI_HISTORY_LOCATION/bemoji-history.txt" 53 | echo -e "database" > "$BEMOJI_DB_LOCATION/emoji.txt" 54 | BEMOJI_LIMIT_RECENT=0 BEMOJI_CLIP_CMD="cat -" BEMOJI_PICKER_CMD="cat -" run bemoji 3>&- 55 | assert_output "database" 56 | } 57 | 58 | -------------------------------------------------------------------------------- /test/resources/test_emoji.txt: -------------------------------------------------------------------------------- 1 | ❤️ red heart 2 | 😀 grinning face 3 | 😃 grinning face with big eyes 4 | 😄 grinning face with smiling eyes 5 | --------------------------------------------------------------------------------