Files
Modus/modules/launcher/plugins/emoji.py
T
2025-06-13 21:00:45 +05:45

123 lines
4.1 KiB
Python

import json
import os
import subprocess
from typing import List, Dict, Any
from . import LauncherPlugin
class EmojiPlugin(LauncherPlugin):
"""Plugin for emoji search and clipboard functionality"""
def __init__(self):
self._emojis = {}
self._load_emojis()
def _load_emojis(self):
"""Load emoji data from the JSON file"""
try:
emoji_file_path = os.path.expanduser("~/Modus/config/emoji.json")
with open(emoji_file_path, "r", encoding="utf-8") as f:
self._emojis = json.load(f)
except Exception as e:
print(f"Failed to load emoji data: {e}")
self._emojis = {}
@property
def name(self) -> str:
return "Emoji"
@property
def category(self) -> str:
return "Utilities"
@property
def icon_name(self) -> str:
return "face-smile-symbolic"
def search(self, query: str) -> List[Dict[str, Any]]:
if not query or len(query) < 2: # Require at least 2 characters
return []
results = []
query_lower = query.lower()
# Search through emojis
for emoji_char, emoji_data in self._emojis.items():
# Search in name, slug, and group
searchable_text = (
emoji_data.get("name", "").lower()
+ " "
+ emoji_data.get("slug", "").lower()
+ " "
+ emoji_data.get("group", "").lower()
)
if query_lower in searchable_text:
results.append(
{
"title": emoji_data.get('name', 'Unknown'),
"description": f"{emoji_data.get('group', 'Unknown')}",
"emoji_icon": emoji_char, # Store the emoji character for display
"action": lambda emoji=emoji_char: self.copy_emoji(emoji),
}
)
# Limit results to prevent overwhelming the UI
if len(results) >= 20:
break
# Sort results by relevance (exact matches first)
def sort_key(item):
name = item["title"].lower()
# Check if query matches the emoji name
if name.startswith(query_lower):
return 0 # Name starts with query
elif query_lower in name:
return 1 # Partial name match
else:
return 2 # Other matches
results.sort(key=sort_key)
return results
def copy_emoji(self, emoji: str):
"""Copy emoji to clipboard using wl-copy"""
# Use a fire-and-forget approach to avoid blocking
try:
# Start wl-copy in the background and don't wait for it
subprocess.Popen(
["wl-copy", emoji], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
print(f"Copied emoji to clipboard: {emoji}")
except FileNotFoundError:
try:
# Fallback to xclip
process = subprocess.Popen(
["xclip", "-selection", "clipboard"],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
text=True,
)
process.stdin.write(emoji)
process.stdin.close()
print(f"Copied emoji to clipboard (xclip): {emoji}")
except (FileNotFoundError, OSError):
print(f"Could not copy emoji to clipboard: {emoji}")
except OSError:
print(f"Could not copy emoji to clipboard: {emoji}")
def get_action_items(self, query: str) -> List[Dict[str, Any]]:
"""Get quick action items for emoji search"""
if not query or len(query) < 2:
return []
# Return a quick action to search for emojis
return [
{
"title": f'Search emojis for "{query}"',
"icon_name": "face-smile-symbolic",
"action": lambda: None, # No specific action needed
}
]