Fix --print flag not working with rofi selector

The rofi callback's stdout is captured by rofi, so print() never
reached the terminal. Callback now writes the selection to a cache
file, and the initial process reads it after rofi exits — where
stdout is the terminal and the original args (including --print)
are available.
This commit is contained in:
Navid Sassan 2026-02-17 21:52:05 +01:00
parent 4468bbfd9d
commit 82159b7e32

View File

@ -13,6 +13,11 @@ from bw_menu.selector import (
) )
def _result_path() -> Path:
cache_dir = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
return Path(cache_dir) / "bw-menu" / "result"
class RofiSelector: class RofiSelector:
def run(self, args) -> Selection | None: def run(self, args) -> Selection | None:
cfg = config.load() cfg = config.load()
@ -21,7 +26,7 @@ class RofiSelector:
if rofi_retv is None: if rofi_retv is None:
self.__launch(keybindings) self.__launch(keybindings)
return None return self.__read_result()
rofi_retv = int(rofi_retv) rofi_retv = int(rofi_retv)
@ -31,27 +36,60 @@ class RofiSelector:
fields = list(keybindings.values()) fields = list(keybindings.values())
# kb-accept-entry → first field
if rofi_retv == 1: if rofi_retv == 1:
rofi_info = os.environ.get("ROFI_INFO", "") rofi_info = os.environ.get("ROFI_INFO", "")
if not rofi_info: if not rofi_info:
return None return None
return Selection(decode_info(rofi_info), fields[0]) self.__write_result(rofi_info, fields[0])
return None
# kb-custom-N: ROFI_RETV 10 + (N-1) # kb-accept-custom → second field
if rofi_retv == 2 and len(fields) > 1:
rofi_info = os.environ.get("ROFI_INFO", "")
if not rofi_info:
return None
self.__write_result(rofi_info, fields[1])
return None
# kb-custom-N: ROFI_RETV 10 + (N-1) → fields[N+1]
custom_index = rofi_retv - 10 custom_index = rofi_retv - 10
field_index = custom_index + 1 field_index = custom_index + 2
if 0 <= field_index < len(fields): if 0 <= field_index < len(fields):
rofi_info = os.environ.get("ROFI_INFO", "") rofi_info = os.environ.get("ROFI_INFO", "")
if not rofi_info: if not rofi_info:
return None return None
return Selection(decode_info(rofi_info), fields[field_index]) self.__write_result(rofi_info, fields[field_index])
return None
return None return None
def __write_result(self, rofi_info: str, field: str):
path = _result_path()
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(f"{rofi_info}\n{field}")
path.chmod(0o600)
def __read_result(self) -> Selection | None:
path = _result_path()
if not path.exists():
return None
try:
data = path.read_text()
parts = data.split("\n", 1)
if len(parts) < 2:
return None
return Selection(decode_info(parts[0]), parts[1])
finally:
path.unlink(missing_ok=True)
def __launch(self, keybindings: dict[str, str]): def __launch(self, keybindings: dict[str, str]):
script = str(Path(sys.argv[0]).resolve()) script = str(Path(sys.argv[0]).resolve())
keys = list(keybindings.keys()) keys = list(keybindings.keys())
# Clean up any stale result from a previous run
_result_path().unlink(missing_ok=True)
cmd = [ cmd = [
"rofi", "rofi",
"-show", "-show",
@ -60,10 +98,12 @@ class RofiSelector:
f"bw:{script} select --selector rofi", f"bw:{script} select --selector rofi",
"-kb-accept-entry", "-kb-accept-entry",
keys[0], keys[0],
"-kb-accept-custom",
"",
] ]
for i, key in enumerate(keys[1:], start=1): if len(keys) > 1:
cmd.extend(["-kb-accept-custom", keys[1]])
else:
cmd.extend(["-kb-accept-custom", ""])
for i, key in enumerate(keys[2:], start=1):
cmd.extend([f"-kb-custom-{i}", key]) cmd.extend([f"-kb-custom-{i}", key])
subprocess.run(cmd) subprocess.run(cmd)