devbits 1.1.2__tar.gz → 1.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devbits
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: A lightweight CLI toolkit for daily development utilities.
5
5
  Author: Bruce Chuang
6
6
  License-Expression: MIT
@@ -1,3 +1,3 @@
1
1
  """devbits: A lightweight CLI toolkit for daily development utilities."""
2
2
 
3
- __version__ = "1.1.2"
3
+ __version__ = "1.1.3"
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
+ import os
4
5
  import sys
5
6
  from pathlib import Path
6
7
 
@@ -12,6 +13,32 @@ from .project import print_tree, rename_files, sample_files, top_sizes
12
13
  from .utils import ensure_exists
13
14
 
14
15
 
16
+ # ---------------------------------------------------------------------------
17
+ # Helper: terminal colors
18
+ # ---------------------------------------------------------------------------
19
+
20
+ _ANSI = {"dir": "\033[1;34m", "file": "\033[0m", "size": "\033[36m", "reset": "\033[0m"}
21
+
22
+
23
+ def _use_color(force: bool | None = None) -> bool:
24
+ """Whether to emit ANSI colors: only on a TTY, unless overridden.
25
+
26
+ Honors the ``NO_COLOR`` convention (https://no-color.org). ``force`` of
27
+ ``True``/``False`` bypasses auto-detection (e.g. from a ``--no-color`` flag).
28
+ """
29
+ if force is not None:
30
+ return force
31
+ if os.environ.get("NO_COLOR"):
32
+ return False
33
+ return sys.stdout.isatty()
34
+
35
+
36
+ def _colorize(text: str, kind: str, enabled: bool) -> str:
37
+ if not enabled:
38
+ return text
39
+ return f"{_ANSI[kind]}{text}{_ANSI['reset']}"
40
+
41
+
15
42
  # ---------------------------------------------------------------------------
16
43
  # Helper: derive default output path from input path
17
44
  # ---------------------------------------------------------------------------
@@ -344,6 +371,8 @@ def build_parser() -> argparse.ArgumentParser:
344
371
  help="Root folder to display. Default: current directory")
345
372
  p.add_argument("--depth", type=int, default=3,
346
373
  help="Maximum depth to traverse. Default: 3")
374
+ p.add_argument("--no-color", action="store_true",
375
+ help="Disable colored output (also honors NO_COLOR).")
347
376
  p.set_defaults(func=cmd_tree)
348
377
 
349
378
  # ── size ───────────────────────────────────────────────────
@@ -362,6 +391,8 @@ def build_parser() -> argparse.ArgumentParser:
362
391
  help="Folder to inspect. Default: current directory")
363
392
  p.add_argument("--top", type=int, default=20,
364
393
  help="Number of items to show. Default: 20")
394
+ p.add_argument("--no-color", action="store_true",
395
+ help="Disable colored output (also honors NO_COLOR).")
365
396
  p.set_defaults(func=cmd_size)
366
397
 
367
398
  # ── renamefiles ────────────────────────────────────────────
@@ -509,13 +540,28 @@ def cmd_contactsheet(args: argparse.Namespace) -> None:
509
540
 
510
541
 
511
542
  def cmd_tree(args: argparse.Namespace) -> None:
543
+ color = _use_color(False if args.no_color else None)
512
544
  for line in print_tree(ensure_exists(args.folder), args.depth):
513
- print(line)
545
+ if not color:
546
+ print(line)
547
+ continue
548
+ # Color only the name, leaving the tree-drawing prefix untouched.
549
+ marker = "── "
550
+ idx = line.rfind(marker)
551
+ split = idx + len(marker) if idx != -1 else 0
552
+ prefix, name = line[:split], line[split:]
553
+ kind = "dir" if name.endswith("/") else "file"
554
+ print(f"{prefix}{_colorize(name, kind, color)}")
514
555
 
515
556
 
516
557
  def cmd_size(args: argparse.Namespace) -> None:
558
+ color = _use_color(False if args.no_color else None)
517
559
  for path, _, size_text in top_sizes(ensure_exists(args.folder), args.top):
518
- print(f"{size_text:>10} {path}")
560
+ kind = "dir" if path.is_dir() else "file"
561
+ label = f"{path}{os.sep}" if path.is_dir() else str(path)
562
+ size_col = _colorize(f"{size_text:>10}", "size", color)
563
+ name_col = _colorize(label, kind, color)
564
+ print(f"{size_col} {name_col}")
519
565
 
520
566
 
521
567
  def cmd_renamefiles(args: argparse.Namespace) -> None:
@@ -108,5 +108,5 @@ def iter_project_tree(root: Path, ignore: Iterable[str], max_depth: int) -> list
108
108
  walk(child, prefix + extension, depth + 1)
109
109
 
110
110
  lines.append(f"{root.name}/")
111
- walk(root, max_depth=max_depth)
111
+ walk(root)
112
112
  return lines
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devbits
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: A lightweight CLI toolkit for daily development utilities.
5
5
  Author: Bruce Chuang
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devbits"
3
- version = "1.1.2"
3
+ version = "1.1.3"
4
4
  description = "A lightweight CLI toolkit for daily development utilities."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes