├── .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 | [](https://ci.martyoeh.me/Marty/bemoji)
4 |
5 | 
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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------