Add hqt palette CLI subcommand (fzf tool launcher)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,68 @@ def tool_cmd(tool, window):
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
PALETTE_ENTRIES = ["nvim", "lazygit", "shell", "clone"]
|
||||
|
||||
# fzf colors matching the Catppuccin Frappé status bar / the Alt+o switcher.
|
||||
_PALETTE_FZF_COLORS = (
|
||||
"bg:#292c3c,bg+:#414559,fg:#c6d0f5,fg+:#c6d0f5,hl:#ef9f76,hl+:#ef9f76,"
|
||||
"pointer:#ef9f76,prompt:#8caaee,info:#838ba7,border:#838ba7"
|
||||
)
|
||||
|
||||
|
||||
def _palette_popup_command(window: str) -> str:
|
||||
"""Shell pipeline for the fzf popup; `window` is baked in as a literal.
|
||||
|
||||
display-popup does NOT format-expand its command, so the window name must be
|
||||
concrete here (run-shell already expanded #{window_name} before `hqt palette`
|
||||
ran). The selected entry runs `hqt tool <choice> <window>`.
|
||||
"""
|
||||
import shlex
|
||||
|
||||
entries = "\\n".join(PALETTE_ENTRIES) + "\\n"
|
||||
return (
|
||||
f"printf '{entries}' | "
|
||||
f"fzf --reverse --no-info --prompt='tool ' --pointer='▌' "
|
||||
f"--color='{_PALETTE_FZF_COLORS}' | "
|
||||
f"xargs -r -I{{}} hqt tool {{}} {shlex.quote(window)}"
|
||||
)
|
||||
|
||||
|
||||
@main.command(name="palette")
|
||||
@click.argument("window")
|
||||
def palette_cmd(window):
|
||||
"""Pop an fzf tool palette for the session in tmux WINDOW (bound to M-p)."""
|
||||
from hqt.config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
svc = _build_session_service()
|
||||
if svc.session_id_for_window(window) is None:
|
||||
subprocess.run(
|
||||
[
|
||||
settings.tmux_path,
|
||||
"display-message",
|
||||
"hqt: open the tool palette from a harness window",
|
||||
]
|
||||
)
|
||||
return
|
||||
subprocess.run(
|
||||
[
|
||||
settings.tmux_path,
|
||||
"display-popup",
|
||||
"-E",
|
||||
"-w",
|
||||
"40%",
|
||||
"-h",
|
||||
"30%",
|
||||
"-T",
|
||||
" open tool ",
|
||||
"-S",
|
||||
"fg=#838ba7",
|
||||
_palette_popup_command(window),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@main.command(name="list")
|
||||
def list_cmd():
|
||||
"""List projects and sessions."""
|
||||
|
||||
@@ -63,3 +63,47 @@ def test_tool_cmd_reports_service_error(monkeypatch, tmp_path):
|
||||
|
||||
assert result.exit_code == 1
|
||||
assert "not an hqt session window" in result.output
|
||||
|
||||
|
||||
def test_palette_cmd_shows_popup_for_session_window(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(
|
||||
"hqt.config.get_settings", lambda: Settings(db_path=tmp_path / "t.db")
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"hqt.sessions.service.SessionService.session_id_for_window",
|
||||
lambda self, window: 5,
|
||||
)
|
||||
runs = []
|
||||
monkeypatch.setattr(cli.subprocess, "run", lambda argv, **kw: runs.append(argv))
|
||||
|
||||
result = CliRunner().invoke(cli.main, ["palette", "hqt-5"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert len(runs) == 1
|
||||
argv = runs[0]
|
||||
assert "display-popup" in argv
|
||||
popup_cmd = argv[-1]
|
||||
assert "fzf" in popup_cmd
|
||||
assert "nvim" in popup_cmd and "clone" in popup_cmd
|
||||
# the window is baked into the command for `hqt tool {} <window>`
|
||||
assert "hqt-5" in popup_cmd
|
||||
|
||||
|
||||
def test_palette_cmd_hints_for_non_session_window(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(
|
||||
"hqt.config.get_settings", lambda: Settings(db_path=tmp_path / "t.db")
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"hqt.sessions.service.SessionService.session_id_for_window",
|
||||
lambda self, window: None,
|
||||
)
|
||||
runs = []
|
||||
monkeypatch.setattr(cli.subprocess, "run", lambda argv, **kw: runs.append(argv))
|
||||
|
||||
result = CliRunner().invoke(cli.main, ["palette", "nvim"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert len(runs) == 1
|
||||
argv = runs[0]
|
||||
assert "display-message" in argv
|
||||
assert "display-popup" not in argv
|
||||
|
||||
Reference in New Issue
Block a user