[meld] Show more parent context in PathLabel (#658)



commit 052db0ea899a6a0ee63cec9fb90ec9683de06416
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Fri Aug 12 09:12:24 2022 +1000

    Show more parent context in PathLabel (#658)
    
    The idea here is that the immediate parent can provide important
    context for the user to know what file they're editing. Many languages
    have common per-folder files (e.g., index.js, __init__.py) that mean
    that just having the file name there without its folder is not very
    useful. We try to help this situation by always including the immediate
    parent folder in our PathLabel display.
    
    In addition to this, some project structures have common parent folders
    (e.g., src) that provide no additional useful context. We try to handle
    this with a heuristic, saying that if the immediate parent path is less
    than five characters long, we will also include its parent. This is a
    rough guess based on some common parent folder names, but is also a
    UI space trade-off to avoid taking up too much toolbar space, or hitting
    ellipsization that we don't want.

 meld/iohelpers.py      | 31 +++++++++++++++++++++----------
 test/test_iohelpers.py | 20 +++++++++++++++++---
 2 files changed, 38 insertions(+), 13 deletions(-)
---
diff --git a/meld/iohelpers.py b/meld/iohelpers.py
index d8ad74db..16e4c960 100644
--- a/meld/iohelpers.py
+++ b/meld/iohelpers.py
@@ -202,7 +202,8 @@ def format_parent_relative_path(parent: Gio.File, descendant: Gio.File) -> str:
     # components will often be the same but that's not guaranteed.
 
     base_path_str = None
-    elided_path = None
+    immediate_parent_strs = []
+    has_elided_path = False
 
     descendant_parent = descendant.get_parent()
     if descendant_parent is None:
@@ -213,15 +214,24 @@ def format_parent_relative_path(parent: Gio.File, descendant: Gio.File) -> str:
     if relative_path_str:
         relative_path = pathlib.Path(relative_path_str)
 
+        # We always try to leave the first and last path segments, to
+        # try to handle e.g., <parent>/<project>/src/<module>/main.py.
         base_path_str = relative_path.parts[0]
-        if len(relative_path.parts) == 1:
-            # No directory components, so we have no elided path
-            # segment
-            elided_path = None
-        else:
-            base_path_gfile = parent.get_child(base_path_str)
-            elided_path = base_path_gfile.get_relative_path(
-                descendant_parent)
+        if len(relative_path.parts) > 1:
+            immediate_parent_strs.append(relative_path.parts[-1])
+
+        # As an additional heuristic, we try to include the second-last
+        # path segment as well, to handle paths like e.g.,
+        # <parent>/<some packge structure>/<module>/src/main.py.
+        # We only do this if the last component is short, to
+        # handle src, dist, pkg, etc. without using too much space.
+        if len(relative_path.parts) > 2 and len(immediate_parent_strs[0]) < 5:
+            immediate_parent_strs.insert(0, relative_path.parts[-2])
+
+        # We have elided paths if we have more parts than our immediate
+        # parent count plus one for the base component.
+        included_path_count = len(immediate_parent_strs) + 1
+        has_elided_path = len(relative_path.parts) > included_path_count
 
     show_parent = not parent.has_parent()
     # It looks odd to have a single component, so if we don't have a
@@ -233,7 +243,8 @@ def format_parent_relative_path(parent: Gio.File, descendant: Gio.File) -> str:
     label_segments = [
         '…' if not show_parent else None,
         base_path_str,
-        '…' if elided_path else None,
+        '…' if has_elided_path else None,
+        *immediate_parent_strs,
         descendant.get_basename(),
     ]
     label_text = format_home_relative_path(parent) if show_parent else ""
diff --git a/test/test_iohelpers.py b/test/test_iohelpers.py
index b4fe0f86..da97aa0a 100644
--- a/test/test_iohelpers.py
+++ b/test/test_iohelpers.py
@@ -64,11 +64,25 @@ def test_find_shared_parent_path(paths, expected_parent):
             '/home/hey/project/foo.txt',
             '…/project/foo.txt',
         ),
-        # Child is a more-than-2-depth child of parent
+        # Child is a 3-depth child of parent
         (
             '/home/hey/',
-            '/home/hey/project/hey/hey/foo.txt',
-            '…/project/…/foo.txt',
+            '/home/hey/project/package/foo.txt',
+            '…/project/package/foo.txt',
+        ),
+        # Child is a more-than-3-depth child of parent, with long
+        # immediate parent
+        (
+            '/home/hey/',
+            '/home/hey/project/package/subpackage/foo.txt',
+            '…/project/…/subpackage/foo.txt',
+        ),
+        # Child is a more-than-3-depth child of parent, with short
+        # immediate parent
+        (
+            '/home/hey/',
+            '/home/hey/project/package/src/foo.txt',
+            '…/project/package/src/foo.txt',
         ),
     ],
 )


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]