The address lane stops eating the columns worth reading

On a Mac the splash's DEVICE column was squeezed to the width of its own
heading, and HARDWARE went with it.

The lane sized itself to the longest target with no cap, and `_name_width`
sizes DEVICE from whatever that leaves. On Windows and Linux the assumption
held -- a MAC is 17 cells, /dev/ttyUSB0 is 12 -- so nothing ever pressed on it.
macOS breaks it twice: CoreBluetooth reports no MAC at all but a per-machine
128-bit UUID, 36 cells of it, and even the ports run long (every Mac carries a
/dev/cu.Bluetooth-Incoming-Port, which is 31). One of those took 36 of the 58
cells a row has, leaving DEVICE six.

So the lane is capped and ellipsizes, which is what the name lane beside it has
always done. The cut takes the **front**: what tells two targets apart is their
tail -- usbmodem1101 from usbmodem1102, ttyUSB0 from ttyUSB1 -- while the head
they share is boilerplate, and cutting the back would draw two different ports
identically, which is the one thing a picker must never do. A CoreBluetooth
UUID reads the same from either end, so the rule that is right for ports costs
the platform that needed the cap nothing. That is also why this is not
`menus.fit_cells`, whose ellipsis keeps the head.

At 20 cells the cap is above every target the other platforms produce, so they
are untouched by it and the change shows up only where something was wrong.
DEVICE goes from 6 cells back to 18.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jean-Pierre MartineauandClaude Opus 5 committed 2026-09-19 00:45:45 -04:00
1 parent 730230461c
commit 1933d725b0
2 files changed
+79 -2

No files matched your search

+41 -2
View File
@@ -153,6 +153,36 @@ def _where(device: DiscoveredDevice) -> str:
return device.target
def _fit_target(text: str, width: int) -> str:
"""Fit a connection target into ``width`` cells, keeping its **end**.
Deliberately not :func:`~meshterm.ui.menus.fit_cells`, which keeps the head: what tells
two targets apart is their *tail* — ``usbmodem1101`` from ``usbmodem1102``,
``ttyUSB0`` from ``ttyUSB1`` — while the head they share (``/dev/cu.``) is boilerplate.
Cutting the front is the cut that leaves the column able to do its one job in a picker,
and cutting the back would render two different ports identically. A CoreBluetooth UUID
is equally identifiable from either end, so the rule that is right for ports costs the
platform that needed the cap nothing.
Args:
text: The target to fit.
width: The cells available. Text already inside it is returned unchanged, so the
platforms that never reach :data:`_ADDRESS_MAX` are untouched.
Returns:
The target, or its tail behind a leading ``…``, measuring at most ``width`` cells.
"""
if cell_len(text) <= width:
return text
keep = max(0, width - 1) # the leading ellipsis costs a cell
tail = ""
for ch in reversed(text):
if cell_len(tail) + cell_len(ch) > keep:
break
tail = ch + tail
return "…" + tail
def _hardware_label(device: DiscoveredDevice, registry: dict[str, RememberedDevice]) -> str:
"""The HARDWARE column text: the remembered firmware model, else the USB vendor.
@@ -670,6 +700,15 @@ async def _remove_network_device(
#: Below this a model string says nothing at all, and the lane is better spent on the name.
_HARDWARE_MIN = 10
#: The widest the PORT / ADDRESS lane may grow before it ellipsizes (see :func:`_fit_target`).
#: A MAC is 17 cells and ``/dev/ttyUSB0`` is 12, so Windows and Linux never reach this and
#: are untouched by it. macOS is why it exists: CoreBluetooth reports no MAC at all but a
#: per-machine 36-cell UUID, and even its serial ports run long
#: (``/dev/cu.Bluetooth-Incoming-Port`` is 31). Uncapped, one of those ate the row —
#: :func:`_name_width` sizes DEVICE from what this lane leaves, so a 36-cell address
#: squeezed the name down to the width of its own heading and the interesting columns with it.
_ADDRESS_MAX = 20
def _name_width(
devices: list[DiscoveredDevice], registry: dict[str, RememberedDevice], other_lanes: int
@@ -765,7 +804,7 @@ def _build_items(
port_label = (
"PORT / ADDRESS" if has_serial and has_address else "ADDRESS" if has_address else "PORT"
)
port_w = max(cell_len(_where(d)) for d in devices)
port_w = min(max(cell_len(_where(d)) for d in devices), _ADDRESS_MAX)
port_w = max(port_w, len(port_label))
# The TYPE column holds a small transport badge (at most 3 cells); its heading is wider,
# so the four-cell "TYPE" label sets the column width and every badge pads out to it.
@@ -806,7 +845,7 @@ def _build_items(
style="device.known" if is_known else "",
)
row.append(" ")
row.append(_pad(_where(device), port_w), style="muted")
row.append(_pad(_fit_target(_where(device), port_w), port_w), style="muted")
row.append(" ")
# The TYPE badge marks the transport: a plug emoji for serial, or the Bluetooth rune
# on its blue badge for BLE. It's built with its own colours, then the column is
+38
View File
@@ -1323,6 +1323,44 @@ def test_device_picker_builds_aligned_columns(tmp_path) -> None:
assert device_rows[0].index("COM5") == device_rows[1].index("/dev/ttyUSB0")
def test_device_picker_address_lane_gives_way_to_the_interesting_columns() -> None:
"""A long target ellipsizes from the left instead of eating the DEVICE lane.
macOS is why: CoreBluetooth reports no MAC but a per-machine 36-cell UUID, and even
its serial ports run long. Uncapped, one address sized the lane and ``_name_width``
sized DEVICE from what was left — so the name shrank to the width of its own heading
and took HARDWARE down with it. Cutting the *front* is what keeps the lane useful:
what tells two targets apart is their tail.
"""
from rich.cells import cell_len
from meshterm.core.discovery import DiscoveredDevice
from meshterm.ui.device_picker import _ADDRESS_MAX, _fit_target, _name_width
# Short targets are returned untouched, so Windows and Linux never notice the cap.
for short in ("COM3", "/dev/ttyUSB0", "C6:B6:26:BC:7F:09", "/dev/cu.usbmodem1101"):
assert _fit_target(short, _ADDRESS_MAX) == short
# A long one is cut at the head and fits the lane it was given.
uuid = "12345678-1234-1234-1234-123456789ABC"
fitted = _fit_target(uuid, _ADDRESS_MAX)
assert cell_len(fitted) <= _ADDRESS_MAX
assert fitted.startswith("…") and fitted.endswith("123456789ABC")
# THE property the cut direction exists for: sibling ports stay tellable apart.
assert _fit_target("/dev/cu.usbmodem1101", 14) != _fit_target("/dev/cu.usbmodem1102", 14)
# And the lane the address was stealing comes back.
devices = [
DiscoveredDevice(transport="ble", address=uuid, name="MeshCore-Johnputer Wardriver"),
DiscoveredDevice("/dev/cu.Bluetooth-Incoming-Port"),
]
uncapped = max(cell_len(d.target) for d in devices)
assert _name_width(devices, {}, min(uncapped, _ADDRESS_MAX) + 4) > _name_width(
devices, {}, uncapped + 4
)
def test_device_picker_names_and_sorts_known_devices(tmp_path) -> None:
"""A confirmed device shows its node name (in white), sorts to the top, and marks type."""
from meshterm.core.device_store import DeviceStore