diff --git a/tests/test_data.py b/tests/test_data.py index c97dcbb..b362ec1 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -68,3 +68,51 @@ def test_run_csv_view_short_rows_are_padded(tmp_path: Path) -> None: assert "3" in output # There should be at least one empty/padded cell visible in output assert " " in output + + +@pytest.mark.skipif(sys.platform == "win32", reason="POSIX temp paths are used for this regression test") +def test_run_csv_view_handles_unquoted_paths_with_spaces(tmp_path: Path) -> None: + from trushell.commands.data import run_csv_view + + directory = tmp_path / "Program Files" + directory.mkdir() + file_path = directory / "users.csv" + file_path.write_text("ID,Name\n1,Ada\n", encoding="utf-8") + + output = _strip_ansi(run_csv_view(str(file_path))) + + assert "ID" in output + assert "Name" in output + assert "Ada" in output + + +@pytest.mark.skipif(sys.platform != "win32", reason="Windows path parsing regression") +def test_run_csv_view_handles_unquoted_windows_paths(tmp_path: Path) -> None: + from trushell.commands.data import run_csv_view + + file_path = tmp_path / "users.csv" + rows = ["ID,Name"] + [f"{i},User {i}" for i in range(1, 52)] + file_path.write_text("\n".join(rows), encoding="utf-8") + + output = _strip_ansi(run_csv_view(str(file_path))) + + assert "User 50" in output + assert "User 51" not in output + assert "...and 1 more" in output + assert "rows" in output + + +@pytest.mark.skipif(sys.platform != "win32", reason="Windows path with spaces regression") +def test_run_csv_view_handles_windows_paths_with_spaces(tmp_path: Path) -> None: + from trushell.commands.data import run_csv_view + + directory = tmp_path / "Program Files" + directory.mkdir() + file_path = directory / "users.csv" + file_path.write_text("ID,Name\n1,Ada\n", encoding="utf-8") + + output = _strip_ansi(run_csv_view(str(file_path))) + + assert "ID" in output + assert "Name" in output + assert "Ada" in output diff --git a/trushell/commands/data.py b/trushell/commands/data.py index 8e63a4c..9c378ba 100644 --- a/trushell/commands/data.py +++ b/trushell/commands/data.py @@ -17,11 +17,27 @@ def _render_markup_message(message: str) -> str: def run_csv_view(args: str) -> str: """Render a CSV file as a Rich table.""" - arguments = shlex.split(args or "") + raw_args = args or "" + raw_path = raw_args.strip().strip("\"'") + arguments = shlex.split(raw_args) if not arguments: return _render_markup_message("[red]Error: No file specified.[/red]") file_path = Path(arguments[0]).expanduser() + if not file_path.exists(): + candidates = [] + if raw_path: + candidates.append(Path(raw_path).expanduser()) + if "\\" in raw_args: + windows_arguments = shlex.split(raw_args, posix=False) + if windows_arguments: + candidates.append(Path(windows_arguments[0].strip("\"'")).expanduser()) + + for candidate in candidates: + if candidate.exists(): + file_path = candidate + break + if not file_path.exists(): return _render_markup_message(f"[red]Error: File '{file_path}' not found.[/red]")