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)
|
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")
|
@main.command(name="list")
|
||||||
def list_cmd():
|
def list_cmd():
|
||||||
"""List projects and sessions."""
|
"""List projects and sessions."""
|
||||||
|
|||||||
@@ -63,3 +63,47 @@ def test_tool_cmd_reports_service_error(monkeypatch, tmp_path):
|
|||||||
|
|
||||||
assert result.exit_code == 1
|
assert result.exit_code == 1
|
||||||
assert "not an hqt session window" in result.output
|
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