Skip to content

Commit ce3325b

Browse files
committed
style: polish fzf pickers with color scheme, ghost text, and separators
Add shared FZF_COLOR theme and _fzf_base_args helper to unify styling across endpoint and history pickers. Adds highlight-line, ghost text placeholders, inline-right info, preview labels, and dim separators between detail sections.
1 parent ed68362 commit ce3325b

1 file changed

Lines changed: 99 additions & 43 deletions

File tree

apick.py

Lines changed: 99 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,26 @@
1717
HISTORY_FILE = os.path.join(os.path.expanduser("~"), ".apick", "history.json")
1818
MAX_HISTORY = 500
1919

20+
FZF_COLOR = (
21+
"dark"
22+
",fg:#c0c0c0"
23+
",fg+:#ffffff"
24+
",bg:-1"
25+
",bg+:#2d2d2d"
26+
",hl:#5f87af"
27+
",hl+:#5fd7ff"
28+
",info:#555555"
29+
",border:#444444"
30+
",label:#8a8a8a"
31+
",preview-label:#8a8a8a"
32+
",prompt:#5fd7ff"
33+
",pointer:#5fd7ff"
34+
",header:#707070"
35+
",separator:#333333"
36+
",scrollbar:#444444"
37+
",preview-border:#333333"
38+
)
39+
2040

2141
def highlight_json(text: str) -> str:
2242
"""Colorize JSON text via jq. Falls back to plain text if jq is unavailable."""
@@ -142,7 +162,10 @@ def format_for_fzf(endpoints: list[dict]) -> str:
142162

143163
def endpoint_detail(spec: dict, ep: dict) -> str:
144164
"""Format detail string for fzf preview pane."""
145-
lines = []
165+
dim = "\033[2m"
166+
reset = "\033[0m"
167+
sep = f"{dim}{'─' * 40}{reset}"
168+
lines = [""]
146169
lines.append(f"\033[1m{ep['method']} {ep['path']}\033[0m")
147170
if ep["summary"]:
148171
lines.append(f" {ep['summary']}")
@@ -153,6 +176,7 @@ def endpoint_detail(spec: dict, ep: dict) -> str:
153176
# Parameters
154177
params = ep.get("parameters", [])
155178
if params:
179+
lines.append(sep)
156180
lines.append("\033[1mParameters:\033[0m")
157181
for p in params:
158182
required = " (required)" if p.get("required") else ""
@@ -167,6 +191,7 @@ def endpoint_detail(spec: dict, ep: dict) -> str:
167191
# Request body
168192
rb = ep.get("requestBody")
169193
if rb:
194+
lines.append(sep)
170195
lines.append("\033[1mRequest Body:\033[0m")
171196
content = rb.get("content", {})
172197
for media, media_obj in content.items():
@@ -179,6 +204,7 @@ def endpoint_detail(spec: dict, ep: dict) -> str:
179204

180205
# Responses
181206
if ep.get("responses"):
207+
lines.append(sep)
182208
lines.append("\033[1mResponses:\033[0m")
183209
for code, resp in ep["responses"].items():
184210
desc = resp.get("description", "") if isinstance(resp, dict) else ""
@@ -234,6 +260,46 @@ def format_schema_tree(schema: dict, indent: int = 0) -> str:
234260
return "\n".join(lines)
235261

236262

263+
def _fzf_base_args(border_label: str, ghost: str, header: str) -> list[str]:
264+
return [
265+
"fzf",
266+
"--ansi",
267+
"--reverse",
268+
"--delimiter",
269+
"\t",
270+
"--with-nth",
271+
"2..",
272+
"--style",
273+
"full",
274+
"--color",
275+
FZF_COLOR,
276+
"--border",
277+
"rounded",
278+
"--border-label",
279+
border_label,
280+
"--border-label-pos",
281+
"2",
282+
"--highlight-line",
283+
"--pointer",
284+
"▶",
285+
"--scrollbar",
286+
"│",
287+
"--ellipsis",
288+
"..",
289+
"--prompt",
290+
" ",
291+
"--ghost",
292+
ghost,
293+
"--info",
294+
"inline-right",
295+
"--separator",
296+
"",
297+
"--header",
298+
header,
299+
"--header-first",
300+
]
301+
302+
237303
def pick_endpoint(endpoints: list[dict], spec: dict, script_path: str) -> dict | None:
238304
"""Shell out to fzf and return the selected endpoint."""
239305
fzf_input = format_for_fzf(endpoints)
@@ -252,29 +318,24 @@ def pick_endpoint(endpoints: list[dict], spec: dict, script_path: str) -> dict |
252318
preview_cmd = (
253319
f"{sys.executable} {script_path} --_preview {{1}} --_spec-file {spec_file_name}"
254320
)
321+
fzf_args = [
322+
*_fzf_base_args(
323+
border_label=border_label,
324+
ghost="type to filter endpoints...",
325+
header=" ↑↓ navigate enter select esc quit",
326+
),
327+
"--preview",
328+
preview_cmd,
329+
"--preview-window",
330+
"right:50%:wrap:border-left",
331+
"--preview-label",
332+
" details ",
333+
"--preview-label-pos",
334+
"2",
335+
]
255336
try:
256337
result = subprocess.run(
257-
[
258-
"fzf",
259-
"--ansi",
260-
"--reverse",
261-
"--delimiter",
262-
"\t",
263-
"--with-nth",
264-
"2..",
265-
"--border",
266-
"rounded",
267-
"--border-label",
268-
border_label,
269-
"--pointer",
270-
"▶",
271-
"--header",
272-
"Select an endpoint (type to search)",
273-
"--preview",
274-
preview_cmd,
275-
"--preview-window",
276-
"right:50%:wrap",
277-
],
338+
fzf_args,
278339
input=fzf_input,
279340
capture_output=True,
280341
text=True,
@@ -528,28 +589,23 @@ def pick_history_entry(entries: list[dict]) -> dict | None:
528589
"""Open fzf over history entries and return the selected one."""
529590
fzf_input = format_history_for_fzf(entries)
530591
try:
592+
fzf_args = [
593+
*_fzf_base_args(
594+
border_label=" apick history ",
595+
ghost="type to filter history...",
596+
header=" ↑↓ navigate enter replay esc quit",
597+
),
598+
"--preview",
599+
"echo {2..}",
600+
"--preview-window",
601+
"down:3:wrap:border-top",
602+
"--preview-label",
603+
" request ",
604+
"--preview-label-pos",
605+
"2",
606+
]
531607
result = subprocess.run(
532-
[
533-
"fzf",
534-
"--ansi",
535-
"--reverse",
536-
"--delimiter",
537-
"\t",
538-
"--with-nth",
539-
"2..",
540-
"--border",
541-
"rounded",
542-
"--border-label",
543-
" history ",
544-
"--pointer",
545-
"▶",
546-
"--header",
547-
"Select a request to replay (type to search)",
548-
"--preview",
549-
"echo {2..}",
550-
"--preview-window",
551-
"down:3:wrap",
552-
],
608+
fzf_args,
553609
input=fzf_input,
554610
capture_output=True,
555611
text=True,

0 commit comments

Comments
 (0)