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 +194 -0
- prezo-0.3.1/README.md +182 -0
- prezo-0.3.1/pyproject.toml +44 -0
- prezo-0.3.1/src/prezo/__init__.py +216 -0
- prezo-0.3.1/src/prezo/app.py +947 -0
- prezo-0.3.1/src/prezo/config.py +247 -0
- prezo-0.3.1/src/prezo/export.py +833 -0
- prezo-0.3.1/src/prezo/images/__init__.py +14 -0
- prezo-0.3.1/src/prezo/images/ascii.py +240 -0
- prezo-0.3.1/src/prezo/images/base.py +111 -0
- prezo-0.3.1/src/prezo/images/chafa.py +137 -0
- prezo-0.3.1/src/prezo/images/iterm.py +126 -0
- prezo-0.3.1/src/prezo/images/kitty.py +360 -0
- prezo-0.3.1/src/prezo/images/overlay.py +291 -0
- prezo-0.3.1/src/prezo/images/processor.py +139 -0
- prezo-0.3.1/src/prezo/images/sixel.py +180 -0
- prezo-0.3.1/src/prezo/parser.py +456 -0
- prezo-0.3.1/src/prezo/screens/__init__.py +21 -0
- prezo-0.3.1/src/prezo/screens/base.py +65 -0
- prezo-0.3.1/src/prezo/screens/blackout.py +60 -0
- prezo-0.3.1/src/prezo/screens/goto.py +99 -0
- prezo-0.3.1/src/prezo/screens/help.py +140 -0
- prezo-0.3.1/src/prezo/screens/overview.py +184 -0
- prezo-0.3.1/src/prezo/screens/search.py +252 -0
- prezo-0.3.1/src/prezo/screens/toc.py +254 -0
- prezo-0.3.1/src/prezo/terminal.py +147 -0
- prezo-0.3.1/src/prezo/themes.py +129 -0
- prezo-0.3.1/src/prezo/widgets/__init__.py +9 -0
- prezo-0.3.1/src/prezo/widgets/image_display.py +117 -0
- prezo-0.3.1/src/prezo/widgets/slide_button.py +72 -0
- prezo-0.3.1/src/prezo/widgets/status_bar.py +240 -0
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
|
+
[](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
|
+
[](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)
|