Files
FastAnime/fastanime/libs/selectors/fzf/selector.py
2025-07-14 20:09:57 +03:00

86 lines
2.5 KiB
Python

import logging
import os
import shutil
import subprocess
from rich.prompt import Prompt
from ....core.config import FzfConfig
from ....core.exceptions import FastAnimeError
from ..base import BaseSelector
logger = logging.getLogger(__name__)
class FzfSelector(BaseSelector):
def __init__(self, config: FzfConfig):
self.config = config
self.executable = shutil.which("fzf")
if not self.executable:
raise FastAnimeError("Please install fzf to use the fzf selector")
os.environ["FZF_DEFAULT_OPTS"] = self.config.opts
self.header_color = config.header_color.split(",")
self.header = "\n".join(
[
f"\033[38;2;{self.header_color[0]};{self.header_color[1]};{self.header_color[2]};m{line}\033[0m"
for line in config.header_ascii_art.replace("\t", "").split("\n")
]
)
def choose(self, prompt, choices, *, preview=None, header=None):
fzf_input = "\n".join(choices)
commands = [
self.executable,
"--prompt",
f"{prompt.title()}: ",
"--header",
self.header,
"--header-first",
]
if preview:
commands.extend(["--preview", preview])
result = subprocess.run(
commands,
input=fzf_input,
stdout=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
return None
return result.stdout.strip()
def confirm(self, prompt, *, default=False):
choices = ["Yes", "No"]
default_choice = "Yes" if default else "No"
result = self.choose(prompt, choices, header=f"Default: {default_choice}")
return result == "Yes"
def ask(self, prompt, *, default=None):
# cleaner to use rich
return Prompt.ask(prompt, default=default)
# -- not going to be used --
commands = [
self.executable,
"--prompt",
f"{prompt.title()}: ",
"--header",
self.header,
"--header-first",
"--print-query",
]
result = subprocess.run(
commands,
input="",
stdout=subprocess.PIPE,
text=True,
check=False,
)
# The output contains the selection (if any) and the query on the last line
lines = result.stdout.strip().splitlines()
return lines[-1] if lines else (default or "")