Skip to content

Commit

Permalink
Merge branch 'mode'
Browse files Browse the repository at this point in the history
  • Loading branch information
fdw committed Jan 31, 2021
2 parents 74cb946 + 3818985 commit 0102792
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 28 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# [NEXT]
## Added
- rofimoji now has a manpage. (#57)
- `rofimoji` can now be called as a modus from rofi! (#44)
- `rofimoji` now has a manpage. (#57)
- There's a new file for [Nerd Font icons](https://www.nerdfonts.com/).

## Changed
Expand Down
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ Fear no more, this script uses the power of [rofi](https://github.com/DaveDavenp
Insert the selected emoji directly, or copy it to the clipboard.
And you can use it to pick any weird character someone got into Unicode, too.

## How does it look?
![Screenshot of rofimoji](screenshot.png?raw=true)

## Usage
### Standalone
1. Run `rofimoji.py`
2. Search for the emoji you want
2. Search for the character you want
3. (optional) Select multiple emoji with `shift+enter`
4. Hit `enter` to insert the emoji directly \
Hit `alt+c` to copy it to the clipboard \
Expand All @@ -16,8 +20,15 @@ And you can use it to pick any weird character someone got into Unicode, too.
5. Maybe select a skin color
6. 🎠

## How does it look?
![Screenshot of rofimoji](screenshot.png?raw=true)
### As a rofi "mode"
1. Call rofi with `rofi -modi "emoji:<path to rofimoji.py>" -show emoji`
2. Search for the character you want
3. Hit `enter` to exexute your default action; \
`Alt+Shift+1` for copying to the clipboard
`Alt+Shift+3` for the "[clipboard](#insertion-method)" insertion method
`alt+1` inserts the most recently used character (`alt+2` for the second most recently one etc.)
4. Maybe select a skin color
5. 🐉

## Insertion method
By default, `rofimoji` types the characters using either `xdotool` or `wtype` (see [Display server support](#display-server-support)). You can enforce this behavior with `--action type` (`-a type`).
Expand Down Expand Up @@ -67,7 +78,15 @@ skin-tone = moderate
## Custom character files
You can define additional character files and load them with `-f` (see [options](#options)). In each line, one 'character' can be defined, followed by a single space character (` `). After that, you can write whatever description you want.

If you think your file is useful to others, you can open a PR to include it in future versions of `rofimoji`.
If you think your file is useful to others, please open a PR to include it in a future version of `rofimoji`.

## Caveats when running `rofimoji` as a rofi "mode"
Running as rofi mode has several drawbacks that cannot be changed:
- Because `rofi` is the main process, `rofimoji` cannot directly type to any window. Only copying the character works, so set the `--action` accordingly.
- You can only select one character at a time.
- The custom keyboard shortcuts are still there, but mapped to `Alt+Shift+1` (on a Qwerty keyboard) etc.

The configuration still works as described. You can have several modes in a `combi` for different character sets, for example, or set a default action and skin tone.

## Installation

Expand All @@ -90,7 +109,7 @@ What else do you need:
For Ubuntu focal: `sudo aptitude install fonts-emojione python3 rofi xdotool xsel` \
For Arch: `sudo pacman -Syu emoji-font python rofi xdotool xsel`

## Updating the emojis
## Updating the characters
If you really, really need to update the characters and cannot wait for the official update:

1. Install Python 3 and `pip install -r requirements.txt` in the `extractors` directory.
Expand Down
8 changes: 6 additions & 2 deletions picker/clipboarder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from subprocess import run

from picker.abstractionhelper import is_wayland, is_installed
from picker.typer import Typer
try:
from picker.abstractionhelper import is_wayland, is_installed
from picker.typer import Typer
except ModuleNotFoundError:
from abstractionhelper import is_wayland, is_installed
from typer import Typer


class Clipboarder:
Expand Down
7 changes: 7 additions & 0 deletions picker/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,10 @@

recents_file_location = data_home / 'rofimoji' / 'recent'
favorites_file_location = data_home / 'rofimoji' / 'favorites'

if os.environ.get('XDG_CACHE_HOME'):
cache_home = Path(os.environ.get('XDG_CACHE_HOME'))
else:
cache_home = Path.home() / '.cache'

cache_file_location = cache_home / 'rofimoji'
103 changes: 84 additions & 19 deletions picker/rofimoji.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@

import configargparse

from picker.clipboarder import Clipboarder
from picker.typer import Typer
from picker.paths import *
try:
from picker.clipboarder import Clipboarder
from picker.typer import Typer
from picker.paths import *
except ModuleNotFoundError:
from clipboarder import Clipboarder
from typer import Typer
from paths import *


class Rofimoji:
Expand Down Expand Up @@ -53,19 +58,6 @@ def __init__(self) -> None:
self.clipboarder = Clipboarder.best_option(self.args.clipboarder)
self.active_window = self.typer.get_active_window()

returncode, stdout = self.open_main_rofi_window()

if returncode == 1:
sys.exit()
else:
if 10 <= returncode <= 19:
characters = self.load_recent_characters(self.args.max_recent)[returncode - 10].strip()
else:
self.choose_action_from_return_code(returncode)
characters = self.process_chosen_characters(stdout.splitlines())

self.execute_action(characters)

def parse_arguments(self) -> argparse.Namespace:
parser = configargparse.ArgumentParser(
description='Select, insert or copy Unicode characters using rofi.',
Expand Down Expand Up @@ -149,6 +141,57 @@ def parse_arguments(self) -> argparse.Namespace:

return parsed_args

def standalone(self) -> None:
returncode, stdout = self.open_main_rofi_window()

if returncode == 1:
sys.exit()
else:
if 10 <= returncode <= 19:
characters = self.load_recent_characters(self.args.max_recent)[returncode - 10].strip()
else:
self.choose_action_from_return_code(returncode)
characters = self.process_chosen_characters(stdout.splitlines())

self.execute_action(characters)

def mode_show_characters(self) -> None:
recent_characters = self.format_recent_characters()

print("\x00markup-rows\x1ftrue\n")
if len(recent_characters) > 0:
print(f"\x00message\x1f{recent_characters}")
print(self.read_character_files())

def mode_act_on_selection(self, chosen_character: str, returncode: int) -> None:
if 10 <= returncode <= 19:
characters = self.load_recent_characters(self.args.max_recent)[returncode - 10].strip()
self.execute_action(characters)
else:
self.choose_action_from_return_code(returncode)
self.save_selection_to_cache(re.match(r'^(?:\u200e(?! ))?(?P<char>.[^ ]*) .*', chosen_character).group('char'), '')
self.mode_select_skin_tone('')

def mode_select_skin_tone(self, processed_character: str) -> None:
(characters, processed_characters) = self.load_selection_from_cache()
processed_characters += processed_character.split(' ')[0]

for character in characters:
if character not in self.skin_tone_selectable_emojis:
processed_characters += character
characters = characters[1:]
else:
self.save_selection_to_cache(characters[1:], processed_characters)
print('\n'.join(
character + modifier + " " + self.fitzpatrick_modifiers[modifier]
for modifier in self.fitzpatrick_modifiers
))
return

cache_file_location.unlink()
self.save_characters_to_recent_file(processed_characters)
self.execute_action(processed_characters)

def choose_action_from_return_code(self, return_code: int):
if return_code == 20:
self.args.action = self.Action.COPY
Expand Down Expand Up @@ -235,8 +278,8 @@ def open_main_rofi_window(self) -> Tuple[int, str]:

def process_chosen_characters(self, chosen_characters: List[str]) -> str:
processed_characters = ''.join(
self.add_skin_tone(re.match(r'^(?:\u200e(?! ))?(?P<char>.[^ ]*) .*', line).group('char'))
for line in chosen_characters
self.add_skin_tone(re.match(r'^(?:\u200e(?! ))?(?P<char>.[^ ]*) .*', character).group('char'))
for character in chosen_characters
)
self.save_characters_to_recent_file(processed_characters)

Expand Down Expand Up @@ -333,9 +376,31 @@ def execute_action(self, characters: str) -> None:
elif self.args.action == self.Action.COPY_UNICODE:
self.clipboarder.copy_characters_to_clipboard(self.get_codepoints(characters))

def save_selection_to_cache(self, characters: str, processed_characters: str) -> None:
with cache_file_location.open('w+') as file:
file.write(f'{self.args.action.value}\n{characters}\n{processed_characters}')

def load_selection_from_cache(self) -> Tuple[str, str]:
cache = cache_file_location.read_text().split('\n')
self.args.action = next(action for action in self.Action if action.value == cache[0].strip())
return cache[1], cache[2]


def main():
Rofimoji()
return_value = os.environ.get('ROFI_RETV')

if return_value is None:
Rofimoji().standalone()
if return_value == "0":
Rofimoji().mode_show_characters()
elif not cache_file_location.is_file():
chosen = sys.argv[-1]
del sys.argv[-1]
Rofimoji().mode_act_on_selection(chosen, int(return_value))
else:
chosen = sys.argv[-1]
del sys.argv[-1]
Rofimoji().mode_select_skin_tone(chosen)


if __name__ == "__main__":
Expand Down
5 changes: 4 additions & 1 deletion picker/typer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from subprocess import run

from picker.abstractionhelper import is_wayland, is_installed
try:
from picker.abstractionhelper import is_wayland, is_installed
except ModuleNotFoundError:
from abstractionhelper import is_wayland, is_installed


class Typer:
Expand Down

0 comments on commit 0102792

Please sign in to comment.