mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-08-06 18:59:37 +00:00
Refine path formatting and testing in MultitestCommand
- Updated path formatting logic in `MultitestCommand` to include a corner marker (┐) for shared paths, enhancing visual clarity. - Improved documentation in `config.ini.example` to reflect changes in path formatting behavior. - Expanded test cases to validate the new corner marker functionality and ensure accurate representation of unique paths with shared prefixes.
This commit is contained in:
+1
-1
@@ -974,7 +974,7 @@ enabled = false
|
||||
# Leave empty to use default format
|
||||
# Example: "Found {path_count} unique path(s) for @[{sender}]:\n{paths}"
|
||||
response_format = @[{sender}] found {path_count} unique path(s):\n{paths}
|
||||
# When true, {paths} uses shared-prefix lines plus tree branches (├ U+251C / └ U+2514; continuations may use ├─ / └─ with U+2500)
|
||||
# When true, {paths} uses shared-prefix lines ending with ┐ U+2510 when branching, then ├ U+251C / └ U+2514 (continuations may use ├─ / └─ with U+2500)
|
||||
condense_paths = false
|
||||
|
||||
[Greeter_Command]
|
||||
|
||||
@@ -21,6 +21,7 @@ _HORIZ = "\u2500" # ─ (BOX DRAWINGS LIGHT HORIZONTAL)
|
||||
# Second-level branches: ├─ / └─ (horizontal continues the tee)
|
||||
_BRANCH_CHILD_INTER = f"{_BRANCH_INTER}{_HORIZ} "
|
||||
_BRANCH_CHILD_LAST = f"{_BRANCH_LAST}{_HORIZ} "
|
||||
_BRANCH_CORNER = "\u2510" # ┐ (marks end of common path before branches)
|
||||
|
||||
|
||||
def _tree_branch_lines_flat(suffixes: list[str]) -> list[str]:
|
||||
@@ -36,7 +37,11 @@ def _tree_branch_lines_flat(suffixes: list[str]) -> list[str]:
|
||||
|
||||
|
||||
def _grouped_suffix_line_specs(non_empty: list[list[str]]) -> list[tuple[str, str]]:
|
||||
"""Build (line_kind, text) rows: 'head' uses ├/└ + space; 'nest' uses ├─/└─ + text."""
|
||||
"""Build (line_kind, text) rows: group by first hop, then longest in-group prefix on the head line.
|
||||
|
||||
So paths 96,e0 / 96,e0,01 / … share head '96,e0' and nest 01, … instead of head '96' with
|
||||
misleading 'e0' as if it were the only endpoint under that branch.
|
||||
"""
|
||||
by_first: dict[str, list[list[str]]] = defaultdict(list)
|
||||
for suf in non_empty:
|
||||
by_first[suf[0]].append(suf[1:])
|
||||
@@ -44,15 +49,19 @@ def _grouped_suffix_line_specs(non_empty: list[list[str]]) -> list[tuple[str, st
|
||||
specs: list[tuple[str, str]] = []
|
||||
for ft in sorted(by_first.keys()):
|
||||
rests = by_first[ft]
|
||||
if len(rests) == 1:
|
||||
r = rests[0]
|
||||
if not r:
|
||||
specs.append(("head", ft))
|
||||
else:
|
||||
specs.append(("head", ",".join([ft, *r])))
|
||||
full_sufs = [[ft, *r] for r in rests]
|
||||
if len(full_sufs) == 1:
|
||||
specs.append(("head", ",".join(full_sufs[0])))
|
||||
continue
|
||||
specs.append(("head", ft))
|
||||
for rem in sorted((r for r in rests if r), key=lambda x: ",".join(x)):
|
||||
inner_lcp = _longest_common_prefix(full_sufs)
|
||||
head_text = ",".join(inner_lcp)
|
||||
remainders = [s[len(inner_lcp) :] for s in full_sufs]
|
||||
nested = sorted((r for r in remainders if r), key=lambda x: ",".join(x))
|
||||
if not nested:
|
||||
specs.append(("head", head_text))
|
||||
continue
|
||||
specs.append(("head", head_text))
|
||||
for rem in nested:
|
||||
specs.append(("nest", ",".join(rem)))
|
||||
return specs
|
||||
|
||||
@@ -73,7 +82,7 @@ def _apply_tee_prefixes(specs: list[tuple[str, str]]) -> list[str]:
|
||||
|
||||
|
||||
def _format_suffix_branch_lines(suffix_tokens: list[list[str]], short_ellipsis: bool) -> list[str]:
|
||||
"""Format suffixes after display LCP: group by first hop, nest continuations with U+2500."""
|
||||
"""Format suffixes after display LCP: group by first hop, in-group LCP on head, nest tails with U+2500."""
|
||||
non_empty = [s for s in suffix_tokens if s]
|
||||
if not non_empty:
|
||||
return _tree_branch_lines_flat(["..."]) if short_ellipsis else []
|
||||
@@ -140,10 +149,12 @@ def _shrink_display_lcp(maximal: list[list[str]], lcp: list[str]) -> list[str]:
|
||||
|
||||
|
||||
def _format_path_cluster(token_lists: list[list[str]], use_brackets: bool) -> list[str]:
|
||||
"""Format a cluster into condensed lines (common prefix + ├/└ and ├─/└─).
|
||||
"""Format a cluster into condensed lines (common prefix + ┐ + ├/└ and ├─/└─).
|
||||
|
||||
Suffixes are grouped by their first hop after the display LCP; multiple variants under the same
|
||||
hop use one ├ line for that hop and ├─/└─ for continuations. The last line of the block uses └/└─.
|
||||
The shared path line ends with ┐ (U+2510) when branch lines follow. Suffixes are grouped by
|
||||
their first hop after the display LCP; within a group, the longest common prefix of all
|
||||
suffixes in that group is one ├ line, then ├─/└─ for each distinct tail. The last line of the
|
||||
block uses └/└─.
|
||||
|
||||
If one path stops exactly where another continues, the displayed LCP is shortened so the shared
|
||||
segment is not mistaken for a single endpoint (e.g. only └ tail after a full shorter path).
|
||||
@@ -166,10 +177,13 @@ def _format_path_cluster(token_lists: list[list[str]], use_brackets: bool) -> li
|
||||
|
||||
if len(lcp) > 0:
|
||||
suffix_tokens = [t[len(lcp) :] for t in maximal]
|
||||
lines = [",".join(lcp)]
|
||||
common = ",".join(lcp)
|
||||
branch_lines = _format_suffix_branch_lines(suffix_tokens, short_ellipsis)
|
||||
if branch_lines:
|
||||
lines = [f"{common} {_BRANCH_CORNER}"]
|
||||
lines.extend(branch_lines)
|
||||
else:
|
||||
lines = [common]
|
||||
return lines
|
||||
|
||||
if len(maximal) == 1:
|
||||
|
||||
@@ -15,6 +15,7 @@ _LAST = "\u2514"
|
||||
_HORIZ = "\u2500"
|
||||
_CHILD_INTER = f"{_INTER}{_HORIZ} "
|
||||
_CHILD_LAST = f"{_LAST}{_HORIZ} "
|
||||
_CORNER = "\u2510" # ┐ after common path
|
||||
|
||||
|
||||
def _make_bot():
|
||||
@@ -162,7 +163,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"e6,0c,85,82,28,1a,cd,7e",
|
||||
f"e6,0c,85,82,28,1a,cd,7e {_CORNER}",
|
||||
f"{_INTER} 01",
|
||||
f"{_INTER} 7a",
|
||||
f"{_CHILD_INTER}09",
|
||||
@@ -183,7 +184,7 @@ class TestCondensePathLines:
|
||||
# LCP shrinks so cc is not the whole “trunk” while dd/ee branch off
|
||||
expected = "\n".join(
|
||||
[
|
||||
"aa,bb",
|
||||
f"aa,bb {_CORNER}",
|
||||
f"{_INTER} cc",
|
||||
f"{_CHILD_INTER}dd",
|
||||
f"{_CHILD_LAST}ee",
|
||||
@@ -197,7 +198,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"cdf1,7e76",
|
||||
f"cdf1,7e76 {_CORNER}",
|
||||
f"{_INTER} 0101",
|
||||
f"{_CHILD_LAST}0970",
|
||||
]
|
||||
@@ -215,7 +216,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"cdf119,860cca",
|
||||
f"cdf119,860cca {_CORNER}",
|
||||
f"{_INTER} 010101",
|
||||
f"{_INTER} e0eed9",
|
||||
f"{_CHILD_LAST}1ed612",
|
||||
@@ -224,20 +225,43 @@ class TestCondensePathLines:
|
||||
assert out == expected
|
||||
|
||||
def test_divergent_routes_with_shared_mid_prefix(self):
|
||||
"""TRM-style: group by first hop (13) so 01 vs 01,1e nest under ├─."""
|
||||
"""TRM-style: in-group LCP 13,01 so 1e nests; 83,09 stays its own branch."""
|
||||
paths = sorted(["41,96,13,01", "41,96,13,01,1e", "41,96,83,09"])
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"41,96",
|
||||
f"{_INTER} 13",
|
||||
f"{_CHILD_INTER}01",
|
||||
f"{_CHILD_INTER}01,1e",
|
||||
f"41,96 {_CORNER}",
|
||||
f"{_INTER} 13,01",
|
||||
f"{_CHILD_INTER}1e",
|
||||
f"{_LAST} 83,09",
|
||||
]
|
||||
)
|
||||
assert out == expected
|
||||
|
||||
def test_shared_second_hop_not_shown_as_endpoint(self):
|
||||
"""W7ZOO-style: 96,e0 shared by all variants; endpoints are 01,09,1e and fc,7a — not 96."""
|
||||
paths = sorted(
|
||||
[
|
||||
"cc,fe,17,b3,7e,96,e0",
|
||||
"cc,fe,17,b3,7e,96,e0,01",
|
||||
"cc,fe,17,b3,7e,96,e0,09",
|
||||
"cc,fe,17,b3,7e,96,e0,1e",
|
||||
"cc,fe,17,b3,7e,fc,7a",
|
||||
]
|
||||
)
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
f"cc,fe,17,b3,7e {_CORNER}",
|
||||
f"{_INTER} 96,e0",
|
||||
f"{_CHILD_INTER}01",
|
||||
f"{_CHILD_INTER}09",
|
||||
f"{_CHILD_INTER}1e",
|
||||
f"{_LAST} fc,7a",
|
||||
]
|
||||
)
|
||||
assert out == expected
|
||||
|
||||
def test_mixed_first_hops_nest_per_group(self):
|
||||
"""Ill Eagle-style: 01 vs 01,1e share a group; 09 and e0 are separate top-level branches."""
|
||||
paths = sorted(
|
||||
@@ -251,7 +275,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"e2,ab,1f,ef,55,21",
|
||||
f"e2,ab,1f,ef,55,21 {_CORNER}",
|
||||
f"{_INTER} 01",
|
||||
f"{_CHILD_INTER}1e",
|
||||
f"{_INTER} 09",
|
||||
@@ -271,7 +295,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"d38a05,c4a86a,067b75,cafee0,1ffbd6,e8154b",
|
||||
f"d38a05,c4a86a,067b75,cafee0,1ffbd6,e8154b {_CORNER}",
|
||||
f"{_INTER} 860cca",
|
||||
f"{_CHILD_LAST}010101",
|
||||
]
|
||||
@@ -292,7 +316,7 @@ class TestCondensePathLines:
|
||||
out = _condense_path_lines(paths)
|
||||
expected = "\n".join(
|
||||
[
|
||||
"d38a05,479198,a837bc,7e7662",
|
||||
f"d38a05,479198,a837bc,7e7662 {_CORNER}",
|
||||
f"{_INTER} e0eed9",
|
||||
f"{_CHILD_INTER}010101",
|
||||
f"{_CHILD_INTER}0970d6",
|
||||
|
||||
Reference in New Issue
Block a user