Repository: streamlink/streamlink

Issue:
cli.utils.progress: relative paths on Windows don't get truncated correctly
### Checklist

- [X] This is a bug report and not a different kind of issue
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed bug reports](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22bug%22)
- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

Latest stable release

### Description

Hello again, I'm the submitter of #4752 and thank you so much for improving it as #4764 said.

But after I updated it to 5.0.0, I found that it doesn't behave as your screen record https://github.com/streamlink/streamlink/pull/4764#issuecomment-1223952285 showed. I recorded some clips in debug / default loglevel in PowerShell / CMD. Here are the clips:


https://user-images.githubusercontent.com/48208459/190840790-f2053d51-9f83-4866-9f24-719364f88352.mp4


https://user-images.githubusercontent.com/48208459/190840793-f376856c-c3d1-4dc4-8399-09e55251035b.mp4


https://user-images.githubusercontent.com/48208459/190840796-1130d9d9-2bc9-4baf-ab16-ada8a905cfcd.mp4


https://user-images.githubusercontent.com/48208459/190840799-b7fb2fca-13ed-45d8-a620-ea5b2fb19e03.mp4

You can see that in Windows it shows either "..." or the full filename and can't show the last strings to fill the row as your record did. And when showing "..." it shows several times a second even in default loglevel.

### Debug log

```text
Please refer to the screen records above.
```



Discussion:

Resolving patch:
diff --git a/src/streamlink_cli/utils/progress.py b/src/streamlink_cli/utils/progress.py
--- a/src/streamlink_cli/utils/progress.py
+++ b/src/streamlink_cli/utils/progress.py
@@ -200,7 +200,7 @@ def format_path(cls, path: PurePath, max_width: int) -> str:
         max_width -= cls.width(path.drive) + cls.width(cls.ELLIPSIS)
 
         # Ignore the path's first part, aka the "anchor" (drive + root)
-        parts = os.path.sep.join(path.parts[1:])
+        parts = os.path.sep.join(path.parts[1:] if path.drive else path.parts)
         truncated = cls.cut(parts, max_width)
 
         return f"{path.drive}{cls.ELLIPSIS}{truncated}"


Test patch:
diff --git a/tests/cli/utils/test_progress.py b/tests/cli/utils/test_progress.py
--- a/tests/cli/utils/test_progress.py
+++ b/tests/cli/utils/test_progress.py
@@ -102,7 +102,8 @@ def test_format_time(self, elapsed, expected):
         assert ProgressFormatter.format_time(elapsed) == expected
 
     _path_posix = PurePosixPath("/foobar/baz/some file name")
-    _path_windows = PureWindowsPath("C:\\foobar\\baz\\some file name")
+    _path_windows_abs = PureWindowsPath("C:\\foobar\\baz\\some file name")
+    _path_windows_rel = PureWindowsPath("foobar\\baz\\some file name")
     _path_windows_unc = PureWindowsPath("\\\\?\\foobar\\baz\\some file name")
 
     @pytest.mark.parametrize("path,max_width,expected", [
@@ -117,17 +118,27 @@ def test_format_time(self, elapsed, expected):
         pytest.param(_path_posix, 16, "…/some file name", id="posix - truncated (all parts except name)"),
         pytest.param(_path_posix, 15, "…some file name", id="posix - truncated (name without separator)"),
         pytest.param(_path_posix, 14, "…ome file name", id="posix - truncated name"),
-        pytest.param(_path_windows, 28, "C:\\foobar\\baz\\some file name", id="windows - full path"),
-        pytest.param(_path_windows, 27, "C:…oobar\\baz\\some file name", id="windows - truncated by 1"),
-        pytest.param(_path_windows, 26, "C:…obar\\baz\\some file name", id="windows - truncated by 2"),
-        pytest.param(_path_windows, 25, "C:…bar\\baz\\some file name", id="windows - truncated by 3"),
-        pytest.param(_path_windows, 24, "C:…ar\\baz\\some file name", id="windows - truncated by 4"),
-        pytest.param(_path_windows, 23, "C:…r\\baz\\some file name", id="windows - truncated by 5"),
-        pytest.param(_path_windows, 22, "C:…\\baz\\some file name", id="windows - truncated by 6"),
-        pytest.param(_path_windows, 21, "C:…baz\\some file name", id="windows - truncated by 7 (cuts off separator)"),
-        pytest.param(_path_windows, 18, "C:…\\some file name", id="windows - truncated (all parts except name)"),
-        pytest.param(_path_windows, 17, "C:…some file name", id="windows - truncated (name without separator)"),
-        pytest.param(_path_windows, 16, "C:…ome file name", id="windows - truncated name"),
+        pytest.param(_path_windows_abs, 28, "C:\\foobar\\baz\\some file name", id="windows abs - full path"),
+        pytest.param(_path_windows_abs, 27, "C:…oobar\\baz\\some file name", id="windows abs - truncated by 1"),
+        pytest.param(_path_windows_abs, 26, "C:…obar\\baz\\some file name", id="windows abs - truncated by 2"),
+        pytest.param(_path_windows_abs, 25, "C:…bar\\baz\\some file name", id="windows abs - truncated by 3"),
+        pytest.param(_path_windows_abs, 24, "C:…ar\\baz\\some file name", id="windows abs - truncated by 4"),
+        pytest.param(_path_windows_abs, 23, "C:…r\\baz\\some file name", id="windows abs - truncated by 5"),
+        pytest.param(_path_windows_abs, 22, "C:…\\baz\\some file name", id="windows abs - truncated by 6"),
+        pytest.param(_path_windows_abs, 21, "C:…baz\\some file name", id="windows abs - truncated by 7 (cuts off separator)"),
+        pytest.param(_path_windows_abs, 18, "C:…\\some file name", id="windows abs - truncated (all parts except name)"),
+        pytest.param(_path_windows_abs, 17, "C:…some file name", id="windows abs - truncated (name without separator)"),
+        pytest.param(_path_windows_abs, 16, "C:…ome file name", id="windows abs - truncated name"),
+        pytest.param(_path_windows_rel, 25, "foobar\\baz\\some file name", id="windows rel - full path"),
+        pytest.param(_path_windows_rel, 24, "…obar\\baz\\some file name", id="windows rel - truncated by 1"),
+        pytest.param(_path_windows_rel, 23, "…bar\\baz\\some file name", id="windows rel - truncated by 2"),
+        pytest.param(_path_windows_rel, 22, "…ar\\baz\\some file name", id="windows rel - truncated by 3"),
+        pytest.param(_path_windows_rel, 21, "…r\\baz\\some file name", id="windows rel - truncated by 4"),
+        pytest.param(_path_windows_rel, 20, "…\\baz\\some file name", id="windows rel - truncated by 5"),
+        pytest.param(_path_windows_rel, 19, "…baz\\some file name", id="windows rel - truncated by 6 (cuts off separator)"),
+        pytest.param(_path_windows_rel, 16, "…\\some file name", id="windows rel - truncated (all parts except name)"),
+        pytest.param(_path_windows_rel, 15, "…some file name", id="windows rel - truncated (name without separator)"),
+        pytest.param(_path_windows_rel, 14, "…ome file name", id="windows rel - truncated name"),
         pytest.param(_path_windows_unc, 29, "\\\\?\\foobar\\baz\\some file name", id="windows UNC - full path"),
         pytest.param(_path_windows_unc, 28, "\\\\?\\…obar\\baz\\some file name", id="windows UNC - truncated by 1"),
         pytest.param(_path_windows_unc, 20, "\\\\?\\…\\some file name", id="windows UNC - truncated (all parts except name)"),