Skip to content

Instantly share code, notes, and snippets.

@altescy
Created August 11, 2022 09:43
Show Gist options
  • Save altescy/f526874b3de783093b11e8cab971e70b to your computer and use it in GitHub Desktop.
Save altescy/f526874b3de783093b11e8cab971e70b to your computer and use it in GitHub Desktop.
Example of interactive selector in Python
from __future__ import annotations
import os
import shutil
import subprocess
class Selector:
SUPPORTED_SELECTOR_COMMANDS = {"fzf", "peco"}
ENVKEY_SELECTOR_COMMAND = "SELECTOR_COMMAND"
def __init__(
self,
selector_command: str | None = None,
) -> None:
self._selector_command = selector_command or self._find_selector_command()
def __call__(self, items: list[str]) -> str:
if self._selector_command:
return self._select_with_command(items)
return self._select_without_command(items)
def _format_list(self, items: list[str]) -> str:
return "\n".join(f"{i}: {item}" for i, item in enumerate(items, start=1))
def _parse_result(self, line: str) -> str:
return line.strip().split(": ", 1)[-1]
def _select_without_command(self, items: list[str]) -> str:
print(self._format_list(items))
index = int(input("select index > ")) - 1
return items[index]
def _select_with_command(self, items: list[str]) -> str:
assert self._selector_command is not None
proc = subprocess.Popen(
[self._selector_command],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=None,
)
stdin = proc.stdin
stdout = proc.stdout
assert stdin is not None
assert stdout is not None
stdin.write(self._format_list(items).encode())
stdin.flush()
stdin.close()
proc.wait()
return self._parse_result(stdout.read().decode())
def _find_selector_command(self) -> str | None:
cmd = os.environ.get(self.ENVKEY_SELECTOR_COMMAND)
if cmd:
return cmd
for cmd in self.SUPPORTED_SELECTOR_COMMANDS:
if shutil.which(cmd):
return cmd
return None
if __name__ == "__main__":
selector = Selector("fzf")
result = selector(["foo", "bar", "baz"])
print(f"{result} was selected.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment