prezo 0.3.1__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.
prezo-0.3.1/PKG-INFO ADDED
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.3
2
+ Name: prezo
3
+ Version: 0.3.1
4
+ Summary: Add your description here
5
+ Author: Stefane Fermigier
6
+ Author-email: Stefane Fermigier <sf@fermigier.com>
7
+ Requires-Dist: textual>=0.89.1
8
+ Requires-Dist: python-frontmatter>=1.1.0
9
+ Requires-Dist: textual-image>=0.8.0
10
+ Requires-Python: >=3.12
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Prezo
14
+
15
+ A TUI-based presentation tool for the terminal, built with [Textual](https://textual.textualize.io/).
16
+
17
+ Display presentations written in Markdown using conventions similar to those of [MARP](https://marp.app/) or [Deckset](https://www.deckset.com/).
18
+
19
+ ## Features (v0.3)
20
+
21
+ - **Markdown presentations** - MARP/Deckset format with `---` slide separators
22
+ - **Live reload** - Auto-refresh when file changes (1s polling)
23
+ - **Keyboard navigation** - Vim-style keys, arrow keys, and more
24
+ - **Slide overview** - Grid view for quick navigation (`o`)
25
+ - **Search** - Find slides by content (`/`)
26
+ - **Table of contents** - Navigate by headings (`t`)
27
+ - **Go to slide** - Jump to specific slide number (`:`)
28
+ - **Presenter notes** - Toggle notes panel (`p`)
29
+ - **Themes** - 6 color schemes (`T` to cycle): dark, light, dracula, solarized-dark, nord, gruvbox
30
+ - **Timer/Clock** - Elapsed time and countdown (`c`)
31
+ - **Edit slides** - Open in $EDITOR (`e`), saves back to source file
32
+ - **Export** - PDF, HTML, PNG, SVG formats with customizable themes and sizes
33
+ - **Image support** - Inline and background images with MARP layout directives (left/right/fit)
34
+ - **Native image viewing** - Press `i` for full-quality image display (iTerm2/Kitty protocols)
35
+ - **Blackout/Whiteout** - Blank screen modes (`b`/`w`)
36
+ - **Command palette** - Quick access to all commands (`Ctrl+P`)
37
+ - **Config file** - Customizable settings via `~/.config/prezo/config.toml`
38
+ - **Recent files** - Tracks recently opened presentations
39
+ - **Position memory** - Remembers last slide position per file
40
+
41
+ ## Demo
42
+
43
+ [![asciicast](https://asciinema.org/a/0rRbYzbq7iyha2wLkN6o4OPcX.svg)](https://asciinema.org/a/0rRbYzbq7iyha2wLkN6o4OPcX)
44
+
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install prezo
50
+ ```
51
+
52
+ Or with [uv](https://docs.astral.sh/uv/):
53
+
54
+ ```bash
55
+ uv tool install prezo
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ```bash
61
+ # View a presentation
62
+ prezo presentation.md
63
+
64
+ # Disable auto-reload
65
+ prezo --no-watch presentation.md
66
+
67
+ # Use custom config
68
+ prezo -c myconfig.toml presentation.md
69
+
70
+ # Set image rendering mode
71
+ prezo --image-mode ascii presentation.md # Options: auto, kitty, sixel, iterm, ascii, none
72
+
73
+ # Export to PDF
74
+ prezo -e pdf presentation.md
75
+
76
+ # Export with options
77
+ prezo -e pdf presentation.md --theme light --size 100x30 --no-chrome
78
+ ```
79
+
80
+ ## Keyboard Shortcuts
81
+
82
+ | Key | Action |
83
+ |-----|--------|
84
+ | `→` / `j` / `Space` | Next slide |
85
+ | `←` / `k` | Previous slide |
86
+ | `Home` / `g` | First slide |
87
+ | `End` / `G` | Last slide |
88
+ | `:` | Go to slide number |
89
+ | `/` | Search slides |
90
+ | `o` | Slide overview |
91
+ | `t` | Table of contents |
92
+ | `p` | Toggle notes panel |
93
+ | `c` | Cycle clock display |
94
+ | `T` | Cycle theme |
95
+ | `b` | Blackout screen |
96
+ | `w` | Whiteout screen |
97
+ | `i` | View image (native quality) |
98
+ | `e` | Edit in $EDITOR |
99
+ | `r` | Reload file |
100
+ | `Ctrl+P` | Command palette |
101
+ | `?` | Help |
102
+ | `q` | Quit |
103
+
104
+ ## Presentation Format
105
+
106
+ Prezo supports standard Markdown with MARP/Deckset conventions:
107
+
108
+ ```markdown
109
+ ---
110
+ title: My Presentation
111
+ theme: default
112
+ ---
113
+
114
+ # First Slide
115
+
116
+ Content here...
117
+
118
+ ---
119
+
120
+ # Second Slide
121
+
122
+ - Bullet points
123
+ - Code blocks
124
+ - Tables
125
+
126
+ ???
127
+ Presenter notes go here (after ???)
128
+
129
+ ---
130
+
131
+ # Third Slide
132
+
133
+ <!-- notes: Alternative notes syntax -->
134
+
135
+ More content...
136
+ ```
137
+
138
+ ## Themes
139
+
140
+ Available themes: `dark`, `light`, `dracula`, `solarized-dark`, `nord`, `gruvbox`
141
+
142
+ Press `T` to cycle through themes during presentation.
143
+
144
+ ## Export Options
145
+
146
+ Prezo supports multiple export formats: PDF, HTML, PNG, and SVG.
147
+
148
+ ```bash
149
+ # PDF export
150
+ prezo -e pdf presentation.md # Default: 80x24, dark theme
151
+ prezo -e pdf presentation.md --theme light # Light theme (for printing)
152
+ prezo -e pdf presentation.md --size 100x30 # Custom dimensions
153
+ prezo -e pdf presentation.md --no-chrome # No window decorations
154
+ prezo -e pdf presentation.md -o slides.pdf # Custom output path
155
+
156
+ # HTML export (single self-contained file)
157
+ prezo -e html presentation.md
158
+
159
+ # Image export (PNG/SVG)
160
+ prezo -e png presentation.md # All slides as PNG
161
+ prezo -e png presentation.md --slide 3 # Single slide (1-indexed)
162
+ prezo -e svg presentation.md --scale 2.0 # SVG with scale factor
163
+ ```
164
+
165
+ PDF/PNG/SVG export requires optional dependencies:
166
+
167
+ ```bash
168
+ pip install prezo[export]
169
+ # or
170
+ pip install cairosvg pypdf
171
+ ```
172
+
173
+ ## Development
174
+
175
+ ```bash
176
+ # Clone and install
177
+ git clone https://github.com/user/prezo.git
178
+ cd prezo
179
+ uv sync
180
+
181
+ # Run
182
+ uv run prezo presentation.md
183
+
184
+ # Run tests
185
+ uv run pytest
186
+
187
+ # Lint
188
+ uv run ruff check .
189
+ uv run ruff format .
190
+ ```
191
+
192
+ ## License
193
+
194
+ MIT
prezo-0.3.1/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # Prezo
2
+
3
+ A TUI-based presentation tool for the terminal, built with [Textual](https://textual.textualize.io/).
4
+
5
+ Display presentations written in Markdown using conventions similar to those of [MARP](https://marp.app/) or [Deckset](https://www.deckset.com/).
6
+
7
+ ## Features (v0.3)
8
+
9
+ - **Markdown presentations** - MARP/Deckset format with `---` slide separators
10
+ - **Live reload** - Auto-refresh when file changes (1s polling)
11
+ - **Keyboard navigation** - Vim-style keys, arrow keys, and more
12
+ - **Slide overview** - Grid view for quick navigation (`o`)
13
+ - **Search** - Find slides by content (`/`)
14
+ - **Table of contents** - Navigate by headings (`t`)
15
+ - **Go to slide** - Jump to specific slide number (`:`)
16
+ - **Presenter notes** - Toggle notes panel (`p`)
17
+ - **Themes** - 6 color schemes (`T` to cycle): dark, light, dracula, solarized-dark, nord, gruvbox
18
+ - **Timer/Clock** - Elapsed time and countdown (`c`)
19
+ - **Edit slides** - Open in $EDITOR (`e`), saves back to source file
20
+ - **Export** - PDF, HTML, PNG, SVG formats with customizable themes and sizes
21
+ - **Image support** - Inline and background images with MARP layout directives (left/right/fit)
22
+ - **Native image viewing** - Press `i` for full-quality image display (iTerm2/Kitty protocols)
23
+ - **Blackout/Whiteout** - Blank screen modes (`b`/`w`)
24
+ - **Command palette** - Quick access to all commands (`Ctrl+P`)
25
+ - **Config file** - Customizable settings via `~/.config/prezo/config.toml`
26
+ - **Recent files** - Tracks recently opened presentations
27
+ - **Position memory** - Remembers last slide position per file
28
+
29
+ ## Demo
30
+
31
+ [![asciicast](https://asciinema.org/a/0rRbYzbq7iyha2wLkN6o4OPcX.svg)](https://asciinema.org/a/0rRbYzbq7iyha2wLkN6o4OPcX)
32
+
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install prezo
38
+ ```
39
+
40
+ Or with [uv](https://docs.astral.sh/uv/):
41
+
42
+ ```bash
43
+ uv tool install prezo
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ```bash
49
+ # View a presentation
50
+ prezo presentation.md
51
+
52
+ # Disable auto-reload
53
+ prezo --no-watch presentation.md
54
+
55
+ # Use custom config
56
+ prezo -c myconfig.toml presentation.md
57
+
58
+ # Set image rendering mode
59
+ prezo --image-mode ascii presentation.md # Options: auto, kitty, sixel, iterm, ascii, none
60
+
61
+ # Export to PDF
62
+ prezo -e pdf presentation.md
63
+
64
+ # Export with options
65
+ prezo -e pdf presentation.md --theme light --size 100x30 --no-chrome
66
+ ```
67
+
68
+ ## Keyboard Shortcuts
69
+
70
+ | Key | Action |
71
+ |-----|--------|
72
+ | `→` / `j` / `Space` | Next slide |
73
+ | `←` / `k` | Previous slide |
74
+ | `Home` / `g` | First slide |
75
+ | `End` / `G` | Last slide |
76
+ | `:` | Go to slide number |
77
+ | `/` | Search slides |
78
+ | `o` | Slide overview |
79
+ | `t` | Table of contents |
80
+ | `p` | Toggle notes panel |
81
+ | `c` | Cycle clock display |
82
+ | `T` | Cycle theme |
83
+ | `b` | Blackout screen |
84
+ | `w` | Whiteout screen |
85
+ | `i` | View image (native quality) |
86
+ | `e` | Edit in $EDITOR |
87
+ | `r` | Reload file |
88
+ | `Ctrl+P` | Command palette |
89
+ | `?` | Help |
90
+ | `q` | Quit |
91
+
92
+ ## Presentation Format
93
+
94
+ Prezo supports standard Markdown with MARP/Deckset conventions:
95
+
96
+ ```markdown
97
+ ---
98
+ title: My Presentation
99
+ theme: default
100
+ ---
101
+
102
+ # First Slide
103
+
104
+ Content here...
105
+
106
+ ---
107
+
108
+ # Second Slide
109
+
110
+ - Bullet points
111
+ - Code blocks
112
+ - Tables
113
+
114
+ ???
115
+ Presenter notes go here (after ???)
116
+
117
+ ---
118
+
119
+ # Third Slide
120
+
121
+ <!-- notes: Alternative notes syntax -->
122
+
123
+ More content...
124
+ ```
125
+
126
+ ## Themes
127
+
128
+ Available themes: `dark`, `light`, `dracula`, `solarized-dark`, `nord`, `gruvbox`
129
+
130
+ Press `T` to cycle through themes during presentation.
131
+
132
+ ## Export Options
133
+
134
+ Prezo supports multiple export formats: PDF, HTML, PNG, and SVG.
135
+
136
+ ```bash
137
+ # PDF export
138
+ prezo -e pdf presentation.md # Default: 80x24, dark theme
139
+ prezo -e pdf presentation.md --theme light # Light theme (for printing)
140
+ prezo -e pdf presentation.md --size 100x30 # Custom dimensions
141
+ prezo -e pdf presentation.md --no-chrome # No window decorations
142
+ prezo -e pdf presentation.md -o slides.pdf # Custom output path
143
+
144
+ # HTML export (single self-contained file)
145
+ prezo -e html presentation.md
146
+
147
+ # Image export (PNG/SVG)
148
+ prezo -e png presentation.md # All slides as PNG
149
+ prezo -e png presentation.md --slide 3 # Single slide (1-indexed)
150
+ prezo -e svg presentation.md --scale 2.0 # SVG with scale factor
151
+ ```
152
+
153
+ PDF/PNG/SVG export requires optional dependencies:
154
+
155
+ ```bash
156
+ pip install prezo[export]
157
+ # or
158
+ pip install cairosvg pypdf
159
+ ```
160
+
161
+ ## Development
162
+
163
+ ```bash
164
+ # Clone and install
165
+ git clone https://github.com/user/prezo.git
166
+ cd prezo
167
+ uv sync
168
+
169
+ # Run
170
+ uv run prezo presentation.md
171
+
172
+ # Run tests
173
+ uv run pytest
174
+
175
+ # Lint
176
+ uv run ruff check .
177
+ uv run ruff format .
178
+ ```
179
+
180
+ ## License
181
+
182
+ MIT
@@ -0,0 +1,44 @@
1
+ [project]
2
+ name = "prezo"
3
+ version = "0.3.1"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Stefane Fermigier", email = "sf@fermigier.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "textual>=0.89.1",
12
+ "python-frontmatter>=1.1.0",
13
+ "textual-image>=0.8.0",
14
+ ]
15
+
16
+ [project.scripts]
17
+ prezo = "prezo:main"
18
+
19
+ [dependency-groups]
20
+ dev = [
21
+ "pytest>=8.0.0",
22
+ "cairosvg>=2.7.0",
23
+ "pypdf>=4.0.0",
24
+ "abilian-devtools>=0.8.0",
25
+ "pytest-asyncio>=1.3.0",
26
+ "ty>=0.0.2",
27
+ ]
28
+ export = [
29
+ "cairosvg>=2.7.0",
30
+ "pypdf>=4.0.0",
31
+ ]
32
+
33
+ [tool.pytest.ini_options]
34
+ testpaths = ["tests"]
35
+ asyncio_mode = "auto"
36
+ asyncio_default_fixture_loop_scope = "function"
37
+
38
+ [build-system]
39
+ requires = ["uv_build>=0.8.4,<0.9.0"]
40
+ build-backend = "uv_build"
41
+
42
+ # [build-system]
43
+ # requires = ["hatchling"]
44
+ # build-backend = "hatchling.build"
@@ -0,0 +1,216 @@
1
+ """Prezo - TUI-based presentation tool."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ # ANSI color codes for error messages
10
+ RED = "\033[91m"
11
+ YELLOW = "\033[93m"
12
+ BOLD = "\033[1m"
13
+ RESET = "\033[0m"
14
+
15
+
16
+ def _error(message: str) -> None:
17
+ """Print an error message and exit."""
18
+ sys.stderr.write(f"{RED}{BOLD}error:{RESET} {message}\n")
19
+ sys.exit(1)
20
+
21
+
22
+ def _warn(message: str) -> None:
23
+ """Print a warning message."""
24
+ sys.stderr.write(f"{YELLOW}{BOLD}warning:{RESET} {message}\n")
25
+
26
+
27
+ def _validate_file(path: Path, must_exist: bool = True) -> Path:
28
+ """Validate a file path and return the resolved path.
29
+
30
+ Args:
31
+ path: The path to validate.
32
+ must_exist: Whether the file must exist.
33
+
34
+ Returns:
35
+ The resolved absolute path.
36
+
37
+ """
38
+ resolved = path.resolve()
39
+
40
+ if must_exist and not resolved.exists():
41
+ _error(
42
+ f"file not found: {path}\n\n"
43
+ "Make sure the file exists and the path is correct."
44
+ )
45
+
46
+ if must_exist and resolved.is_dir():
47
+ _error(
48
+ f"expected a file, got a directory: {path}\n\nProvide a path to a .md file."
49
+ )
50
+
51
+ if must_exist and resolved.suffix.lower() not in (".md", ".markdown"):
52
+ _warn(
53
+ f"file '{path.name}' does not have a .md extension "
54
+ "- treating as markdown anyway"
55
+ )
56
+
57
+ return resolved
58
+
59
+
60
+ def main() -> None:
61
+ """Entry point for Prezo."""
62
+ parser = argparse.ArgumentParser(
63
+ prog="prezo",
64
+ description="TUI-based presentation tool for Markdown slides",
65
+ epilog="For more information, visit: https://github.com/abilian/prezo",
66
+ )
67
+ parser.add_argument(
68
+ "file",
69
+ nargs="?",
70
+ help="Path to the presentation file (.md)",
71
+ )
72
+ parser.add_argument(
73
+ "--export",
74
+ "-e",
75
+ metavar="FORMAT",
76
+ choices=["pdf", "html", "png", "svg"],
77
+ help="Export presentation to format (pdf, html, png, svg)",
78
+ )
79
+ parser.add_argument(
80
+ "--slide",
81
+ metavar="NUM",
82
+ type=int,
83
+ help="Export only slide number NUM (1-indexed, for png/svg export)",
84
+ )
85
+ parser.add_argument(
86
+ "--output",
87
+ "-o",
88
+ metavar="PATH",
89
+ help="Output path for export (default: same name with new extension)",
90
+ )
91
+ parser.add_argument(
92
+ "--theme",
93
+ "-t",
94
+ metavar="NAME",
95
+ default="dark",
96
+ help="Theme for export (dark, light, dracula, solarized-dark, nord, gruvbox)",
97
+ )
98
+ parser.add_argument(
99
+ "--size",
100
+ "-s",
101
+ metavar="WxH",
102
+ default="80x24",
103
+ help="Screen size for export as WIDTHxHEIGHT (default: 80x24)",
104
+ )
105
+ parser.add_argument(
106
+ "--no-chrome",
107
+ action="store_true",
108
+ help="Export without window decorations (for printing)",
109
+ )
110
+ parser.add_argument(
111
+ "--scale",
112
+ metavar="FACTOR",
113
+ type=float,
114
+ default=2.0,
115
+ help="Scale factor for PNG export (default: 2.0 for higher resolution)",
116
+ )
117
+ parser.add_argument(
118
+ "--no-watch",
119
+ action="store_true",
120
+ help="Disable file watching for auto-reload",
121
+ )
122
+ parser.add_argument(
123
+ "--config",
124
+ "-c",
125
+ metavar="PATH",
126
+ help="Path to custom config file (default: ~/.config/prezo/config.toml)",
127
+ )
128
+ parser.add_argument(
129
+ "--image-mode",
130
+ metavar="MODE",
131
+ choices=["auto", "kitty", "sixel", "iterm", "ascii", "none"],
132
+ help="Image rendering mode (auto, kitty, sixel, iterm, ascii, none)",
133
+ )
134
+
135
+ args = parser.parse_args()
136
+
137
+ # Load config from custom path or default
138
+ from .config import load_config # noqa: PLC0415
139
+
140
+ config_path = Path(args.config) if args.config else None
141
+ if config_path and not config_path.exists():
142
+ _error(f"config file not found: {config_path}")
143
+
144
+ config = load_config(config_path)
145
+
146
+ # Override image mode if specified
147
+ if args.image_mode:
148
+ config.images.mode = args.image_mode
149
+
150
+ if args.export:
151
+ if not args.file:
152
+ _error(
153
+ "--export requires a presentation file\n\n"
154
+ "Usage: prezo -e pdf presentation.md"
155
+ )
156
+
157
+ # Validate source file
158
+ source_path = _validate_file(Path(args.file))
159
+
160
+ # Parse size
161
+ try:
162
+ width, height = map(int, args.size.lower().split("x"))
163
+ except ValueError:
164
+ _error(
165
+ f"invalid size format: {args.size}\n\n"
166
+ "Use WIDTHxHEIGHT format (e.g., 80x24, 100x30)"
167
+ )
168
+
169
+ if args.export == "html":
170
+ from .export import run_html_export # noqa: PLC0415
171
+
172
+ sys.exit(
173
+ run_html_export(
174
+ str(source_path),
175
+ args.output,
176
+ theme=args.theme,
177
+ ),
178
+ )
179
+ elif args.export in ("png", "svg"):
180
+ from .export import run_image_export # noqa: PLC0415
181
+
182
+ sys.exit(
183
+ run_image_export(
184
+ str(source_path),
185
+ args.output,
186
+ output_format=args.export,
187
+ theme=args.theme,
188
+ width=width,
189
+ height=height,
190
+ chrome=not args.no_chrome,
191
+ slide_num=args.slide,
192
+ scale=args.scale,
193
+ ),
194
+ )
195
+ else:
196
+ from .export import run_export # noqa: PLC0415
197
+
198
+ sys.exit(
199
+ run_export(
200
+ str(source_path),
201
+ args.output,
202
+ theme=args.theme,
203
+ width=width,
204
+ height=height,
205
+ chrome=not args.no_chrome,
206
+ ),
207
+ )
208
+ else:
209
+ from .app import run_app # noqa: PLC0415
210
+
211
+ # Validate file if provided
212
+ file_path = None
213
+ if args.file:
214
+ file_path = _validate_file(Path(args.file))
215
+
216
+ run_app(file_path, watch=not args.no_watch, config=config)