Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/memories/gf_routing_and_carriers.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,6 @@ The Matrix table prints the same line through `_print_matrix_carrier_legend`,
naming each code by Matrix's `shortName`. Both go through
`_print_carrier_legend_line`, which collapses the whitespace runs of an entry, a
newline and a tab included, to one space, so a name cannot break the legend over
two lines.
two lines. When the legend outgrows the console it breaks only between entries,
never between a code and its name; Rich breaks at any space, a no-break space
included, so `_print_carrier_legend_line` picks the break itself.
26 changes: 21 additions & 5 deletions src/flight_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5069,12 +5069,28 @@ def _render_search(


def _print_carrier_legend_line(named: Mapping[str, str | None]) -> None:
"""The one `Carriers:` line both tables print, each named code once. An entry's
"""The `Carriers:` legend both tables print, each named code once. An entry's
whitespace runs, a newline and a tab included, collapse to one space so a name
cannot break the legend over two lines; a table with no named code prints none."""
if any(named.values()):
entries = (" ".join(f"{code} {name}".split()) for code, name in named.items() if name)
console.print("[dim]Carriers: " + _safe_text(" · ".join(entries)) + "[/]")
cannot break the legend over two lines; a table with no named code prints none.
When it outgrows the console it breaks only between entries, never between a
code and its name: Rich breaks at any space, a no-break space included, so the
break is chosen here, and an entry wider than the console is left for Rich to fold."""
entries = [
" ".join(f"{code} {name}".translate(_CTRL).split()) for code, name in named.items() if name
]
entries = [entry for entry in entries if entry]
if not entries:
return
# The prefix counts toward the first line, so the first entry is measured too.
lines = ["Carriers:"]
for i, entry in enumerate(entries):
piece = entry + (" ·" if i < len(entries) - 1 else "")
if cell_len(lines[-1] + " " + piece) <= console.width:
lines[-1] += " " + piece
else:
lines.append(piece)
for line in lines:
console.print("[dim]" + _safe_text(line) + "[/]")


def _print_matrix_carrier_legend(shown: Sequence[Itinerary]) -> None:
Expand Down
10 changes: 10 additions & 0 deletions tests/test_carrier_legend_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ def test_memo_says_a_legend_name_cannot_break_the_line() -> None:
"collapses the whitespace runs of an entry, a newline and a tab included, to one "
"space, so a name cannot break the legend over two lines"
) in memo


def test_memo_says_a_wrapped_legend_breaks_only_between_entries() -> None:
text = (_ROOT / "docs/memories/gf_routing_and_carriers.md").read_text()
memo = " ".join(text.split())
assert (
"When the legend outgrows the console it breaks only between entries, never between a "
"code and its name; Rich breaks at any space, a no-break space included, so "
"`_print_carrier_legend_line` picks the break itself."
) in memo
25 changes: 25 additions & 0 deletions tests/test_gf_carrier_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,31 @@ def test_a_narrow_console_wraps_the_legend_within_its_width(
assert _LEGEND in " ".join(" ".join(lines).split())


def test_a_wrapping_legend_keeps_each_code_with_its_name(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""At 40 columns Rich alone ends the first line on `F9`, apart from its name."""
lines = _printed(monkeypatch, [_row(("MX", "100")), _row(("F9", "200"))], width=40)
start = next(i for i, ln in enumerate(lines) if ln.startswith("Carriers:"))
assert [ln.rstrip() for ln in lines[start:]] == [
"Carriers: MX Breeze Airways ·",
"F9 Frontier Airlines",
]


def test_a_legend_entry_that_fits_the_console_is_never_split_the_first_included(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""`LH Lufthansa ·` fits 14 columns; with `Carriers: ` before it, it needs 24."""
split: list[int] = []
for width in range(14, 61):
lines = _printed(monkeypatch, [_row(("LH", "1")), _row(("B6", "2"))], width=width)
legend = lines[next(i for i, ln in enumerate(lines) if ln.startswith("Carriers:")) :]
if not all(any(e in ln for ln in legend) for e in ("LH Lufthansa", "B6 JetBlue")):
split.append(width)
assert split == []


def test_a_search_prints_the_legend_under_its_table(gf_session: Callable[..., Any]) -> None:
body = _answering(
_ds1("ds1_jfk_lhr_tfu.json"), origin="JFK", destination="LHR", date=_DEP.isoformat()
Expand Down
Loading