Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,34 @@ Combine options:
ticklе /path/to/repo --markers TODO,FIXME --ignore "tests,venv" --sort marker --reverse --tree-collapse
```

## Exporting Output for Printing

You can export tickle's output to a plain text file for easy printing or sharing. Use the `--export` flag:

```bash
tickle [options] --export output.txt
```

- The output will be saved to `output.txt` in plain text format.
- If the file already exists, it will be overwritten (a warning will be shown).
- After export, tickle will display a confirmation message with the file path.

**Example:**

```bash
tickle --markers TODO,FIXME --export my_tasks.txt
```

You can then print the file using your operating system's tools. For example, on Windows:

```bash
notepad /p my_tasks.txt
```

Or open and print with any text editor.

---

## Configuration

Tired of typing the same flags every time? Configuration files let you set persistent defaults for ignore patterns, markers, output format, and more. Share configuration across your team via `pyproject.toml`, or maintain personal preferences in your user config.
Expand Down
16 changes: 15 additions & 1 deletion src/tickle/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,18 @@ def handle_scan_command(args):
git_verbose=merged["git_verbose"],
tree_collapse=merged["tree_collapse"],
scan_directory=merged["path"],
no_color=bool(getattr(args, "export", None)),
)
output = formatter.format(tasks)
print(output)
if hasattr(args, 'export') and args.export:
export_path = Path(args.export)
overwrite = export_path.exists()
export_path.write_text(output, encoding="utf-8")
if overwrite:
print(f"[tickle] Warning: Overwrote existing file: {export_path}")
print(f"[tickle] Output exported to: {export_path}")
else:
print(output)


def main():
Expand Down Expand Up @@ -205,6 +214,11 @@ def main():
parser.add_argument(
"--verbose", action="store_true", help="Show which config file is being used"
)
parser.add_argument(
"--export",
type=str,
help="Export output to a plain text file (overwrites if exists)"
)
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")

args = parser.parse_args()
Expand Down
13 changes: 9 additions & 4 deletions src/tickle/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,19 @@ class TreeFormatter(Formatter):
"CHECKBOX": "green",
}

def __init__(self, git_verbose: bool = False, show_details: bool = True, scan_directory: str = "."):
def __init__(self, git_verbose: bool = False, show_details: bool = True, scan_directory: str = ".", no_color: bool = False):
"""Initialize the tree formatter.

Args:
git_verbose: Whether to show full git commit info (hash and message)
show_details: Whether to show individual task details (False shows counts only)
scan_directory: Directory being scanned (used for root label)
no_color: Disable color/ANSI codes in output (for export)
"""
self.git_verbose = git_verbose
self.show_details = show_details
self.scan_directory = scan_directory
self.no_color = no_color

def format(self, tasks: list[Task]) -> str:
"""Format tasks as a hierarchical tree."""
Expand All @@ -157,7 +159,7 @@ def format(self, tasks: list[Task]) -> str:
tree = self._build_tree(tasks)

# Render to string using Console
console = Console(legacy_windows=False)
console = Console(legacy_windows=False, color_system=None, force_terminal=not self.no_color, no_color=self.no_color)
with console.capture() as capture:
console.print(tree)

Expand Down Expand Up @@ -354,7 +356,8 @@ def get_formatter(
format_type: str,
git_verbose: bool = False,
tree_collapse: bool = False,
scan_directory: str = "."
scan_directory: str = ".",
no_color: bool = False,
) -> Formatter:
"""Factory function to get the appropriate formatter.

Expand All @@ -363,6 +366,7 @@ def get_formatter(
git_verbose: Whether to show full git commit info (hash and message)
tree_collapse: Show only directory structure with counts (tree format only)
scan_directory: Directory being scanned (tree format only)
no_color: Disable color/ANSI codes in output (for export)

Returns:
An instance of the appropriate Formatter subclass.
Expand All @@ -378,7 +382,8 @@ def get_formatter(
return TreeFormatter(
git_verbose=git_verbose,
show_details=not tree_collapse,
scan_directory=scan_directory
scan_directory=scan_directory,
no_color=no_color
)
else:
raise ValueError(f"Unknown format type: {format_type}")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,14 @@ def test_main_combined_flags(self, sample_repo, capsys):

def test_version_flag(self, capsys):
"""Test --version flag displays version."""
from tickle import __version__
with mock.patch("sys.argv", ["tickle", "--version"]):
with pytest.raises(SystemExit) as exc_info:
main()

assert exc_info.value.code == 0
captured = capsys.readouterr()
assert "0.1.0" in captured.out
assert __version__ in captured.out

def test_sort_by_marker(self, capsys):
"""Test --sort marker flag."""
Expand Down