prosaic-app 0.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.
- prosaic_app-0.1.3/LICENSE +21 -0
- prosaic_app-0.1.3/PKG-INFO +168 -0
- prosaic_app-0.1.3/README.md +136 -0
- prosaic_app-0.1.3/prosaic/__init__.py +3 -0
- prosaic_app-0.1.3/prosaic/__main__.py +149 -0
- prosaic_app-0.1.3/prosaic/app.py +283 -0
- prosaic_app-0.1.3/prosaic/config.py +114 -0
- prosaic_app-0.1.3/prosaic/core/__init__.py +17 -0
- prosaic_app-0.1.3/prosaic/core/markdown.py +78 -0
- prosaic_app-0.1.3/prosaic/core/metrics.py +89 -0
- prosaic_app-0.1.3/prosaic/screens/__init__.py +6 -0
- prosaic_app-0.1.3/prosaic/screens/dashboard.py +166 -0
- prosaic_app-0.1.3/prosaic/screens/editor.py +243 -0
- prosaic_app-0.1.3/prosaic/themes/__init__.py +16 -0
- prosaic_app-0.1.3/prosaic/themes/dark.tcss +558 -0
- prosaic_app-0.1.3/prosaic/themes/light.tcss +562 -0
- prosaic_app-0.1.3/prosaic/widgets/__init__.py +8 -0
- prosaic_app-0.1.3/prosaic/widgets/file_tree.py +55 -0
- prosaic_app-0.1.3/prosaic/widgets/outline.py +47 -0
- prosaic_app-0.1.3/prosaic/widgets/spell_text_area.py +204 -0
- prosaic_app-0.1.3/prosaic/widgets/statusbar.py +122 -0
- prosaic_app-0.1.3/prosaic/wizard.py +135 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/PKG-INFO +168 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/SOURCES.txt +28 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/dependency_links.txt +1 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/entry_points.txt +2 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/requires.txt +12 -0
- prosaic_app-0.1.3/prosaic_app.egg-info/top_level.txt +5 -0
- prosaic_app-0.1.3/pyproject.toml +54 -0
- prosaic_app-0.1.3/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Deepansh Khurana
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prosaic-app
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A writer-first terminal writing app
|
|
5
|
+
Author: Deepansh Khurana
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/deepanshkhurana/prosaic
|
|
8
|
+
Project-URL: Repository, https://github.com/deepanshkhurana/prosaic
|
|
9
|
+
Keywords: writing,terminal,markdown,tui
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Text Editors
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: textual[syntax]>=0.50.0
|
|
22
|
+
Requires-Dist: click>=8.1.0
|
|
23
|
+
Requires-Dist: platformdirs>=4.0.0
|
|
24
|
+
Requires-Dist: gitpython>=3.1.0
|
|
25
|
+
Requires-Dist: pyspellchecker>=0.8.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: textual-dev>=1.0.0; extra == "dev"
|
|
29
|
+
Provides-Extra: grammar
|
|
30
|
+
Requires-Dist: language-tool-python>=2.8.0; extra == "grammar"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Prosaic
|
|
34
|
+
|
|
35
|
+
A writer-first terminal writing app built with Python and Textual, built with the assistance of LLM/Copilot tools.
|
|
36
|
+
|
|
37
|
+
## Motivation
|
|
38
|
+
|
|
39
|
+
I write on multiple devices (an iPad, a laptop, even more), and I wanted a quick way to start every day, get some frontmatter ready for my daily pieces on [journal.coffee](https://journal.coffee), jot down notes and even work on books. I have tried several software, some stellar, some half-assed, some bloated, some minimal, but I felt like I needed something of my own.
|
|
40
|
+
|
|
41
|
+
So, I decided that the best way to go about it is to have a TUI. I can access it from anywhere, and mostly, it will do the job. This way, I can access it from a terminal app on the iPad or Windows (cue: Termix on a browser) and on the Macbook. Hence, Prosaic was born.
|
|
42
|
+
|
|
43
|
+
**Full disclosure:** I did rely on LLMs to make it, but as much as I could, I tried to get it to follow best practices, good architecture, and clean code principles.
|
|
44
|
+
|
|
45
|
+
## Publish with Ode
|
|
46
|
+
|
|
47
|
+
Looking somewhere to publish your writing that is philosophically compatible with Prosaic? Check out [Ode](https://ode.dimwit.me/). You can also go to the [GitHub](https://github.com/DeepanshKhurana/ode/) directly.
|
|
48
|
+
|
|
49
|
+
> Ode is for writers who want to publish in an aesthetically pleasing website, ignoring the bells and whistles of the modern internet. It is opinionated, minimal, and easy to use, guided by an [Ethos](https://docs.ode.dimwit.me/ethos) that prioritizes the craft of writing and the joy of reading over metrics and engagement.
|
|
50
|
+
|
|
51
|
+
## Screenshots
|
|
52
|
+
|
|
53
|
+
| | |
|
|
54
|
+
|---|---|
|
|
55
|
+
|  |  |
|
|
56
|
+
|  |  |
|
|
57
|
+
|  |  |
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Install (requires Python 3.11+)
|
|
63
|
+
pipx install prosaic
|
|
64
|
+
|
|
65
|
+
# Run (first launch runs setup wizard)
|
|
66
|
+
prosaic
|
|
67
|
+
|
|
68
|
+
# Re-run setup wizard anytime
|
|
69
|
+
prosaic --setup
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
- **Markdown-first**: Live outline, word counting
|
|
75
|
+
- **Focus mode**: Hide everything except your writing
|
|
76
|
+
- **Reader mode**: Distraction-free reading
|
|
77
|
+
- **Continue writing**: Resume your last edited document
|
|
78
|
+
- **Daily metrics**: Track words and characters written each day
|
|
79
|
+
- **Git-ready**: Archive is Git-initialized for versioning
|
|
80
|
+
|
|
81
|
+
## Keybindings
|
|
82
|
+
|
|
83
|
+
| Category | Key | Action |
|
|
84
|
+
|----------|-----|--------|
|
|
85
|
+
| Dashboard | `c` | Continue writing (if last file exists) |
|
|
86
|
+
| Dashboard | `p` | Write a piece |
|
|
87
|
+
| Dashboard | `b` | Work on a book |
|
|
88
|
+
| Dashboard | `n` | Add a note |
|
|
89
|
+
| Dashboard | `r` | Read notes |
|
|
90
|
+
| Dashboard | `f` | Find files |
|
|
91
|
+
| Dashboard | `?` | Help |
|
|
92
|
+
| Dashboard | `q` | Quit |
|
|
93
|
+
| Editor | `Ctrl+e` | Toggle file tree |
|
|
94
|
+
| Editor | `Ctrl+o` | Toggle outline |
|
|
95
|
+
| Editor | `Ctrl+s` | Save |
|
|
96
|
+
| Editor | `Ctrl+q` | Go home |
|
|
97
|
+
| Editor | `F5` | Focus mode |
|
|
98
|
+
| Editor | `F6` | Reader mode |
|
|
99
|
+
| Writing | `Ctrl+z` | Undo |
|
|
100
|
+
| Writing | `Ctrl+y` | Redo |
|
|
101
|
+
| Writing | `Ctrl+x` | Cut |
|
|
102
|
+
| Writing | `Ctrl+c` | Copy |
|
|
103
|
+
| Writing | `Ctrl+v` | Paste |
|
|
104
|
+
| Writing | `Ctrl+a` | Select all |
|
|
105
|
+
|
|
106
|
+
## Themes
|
|
107
|
+
|
|
108
|
+
- **Prosaic Light** (default): Warm white background with brick accents
|
|
109
|
+
- **Prosaic Dark**: Deep charcoal with warm tan accents
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Light mode (default)
|
|
113
|
+
prosaic
|
|
114
|
+
|
|
115
|
+
# Dark mode
|
|
116
|
+
prosaic --dark
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Configuration
|
|
120
|
+
|
|
121
|
+
Config location (in order of priority):
|
|
122
|
+
1. `PROSAIC_CONFIG_DIR` env var (explicit override)
|
|
123
|
+
2. `$XDG_CONFIG_HOME/prosaic/` (Linux standard)
|
|
124
|
+
3. `~/.config/prosaic/` (default)
|
|
125
|
+
|
|
126
|
+
Override with environment variable:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
PROSAIC_CONFIG_DIR=~/custom/path prosaic
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Git Integration
|
|
133
|
+
|
|
134
|
+
If your chosen archive directory already contains a git repository, the wizard will:
|
|
135
|
+
|
|
136
|
+
- Detect the existing `.git` directory
|
|
137
|
+
- Inherit the repository (no re-initialization)
|
|
138
|
+
- Read the remote URL if configured
|
|
139
|
+
- Prompt for a remote URL if none exists
|
|
140
|
+
- Store this info in `settings.json`
|
|
141
|
+
|
|
142
|
+
Example `settings.json`:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"setup_complete": true,
|
|
147
|
+
"archive_dir": "/Users/you/Prosaic",
|
|
148
|
+
"init_git": true,
|
|
149
|
+
"git_remote": "git@github.com:you/writing.git",
|
|
150
|
+
"git_inherited": true,
|
|
151
|
+
"last_file": "/Users/you/Prosaic/pieces/2026-02-21-example.md"
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Archive Structure
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
~/Prosaic/ # Default archive (configurable)
|
|
159
|
+
pieces/ # Pieces with preloaded markdown frontmatter
|
|
160
|
+
books/ # Long-form projects with Outline already open
|
|
161
|
+
notes.md # Quick notes with auto date headers
|
|
162
|
+
metrics.json # Daily statistics for archival and display
|
|
163
|
+
.git/ # Version control
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Prosaic
|
|
2
|
+
|
|
3
|
+
A writer-first terminal writing app built with Python and Textual, built with the assistance of LLM/Copilot tools.
|
|
4
|
+
|
|
5
|
+
## Motivation
|
|
6
|
+
|
|
7
|
+
I write on multiple devices (an iPad, a laptop, even more), and I wanted a quick way to start every day, get some frontmatter ready for my daily pieces on [journal.coffee](https://journal.coffee), jot down notes and even work on books. I have tried several software, some stellar, some half-assed, some bloated, some minimal, but I felt like I needed something of my own.
|
|
8
|
+
|
|
9
|
+
So, I decided that the best way to go about it is to have a TUI. I can access it from anywhere, and mostly, it will do the job. This way, I can access it from a terminal app on the iPad or Windows (cue: Termix on a browser) and on the Macbook. Hence, Prosaic was born.
|
|
10
|
+
|
|
11
|
+
**Full disclosure:** I did rely on LLMs to make it, but as much as I could, I tried to get it to follow best practices, good architecture, and clean code principles.
|
|
12
|
+
|
|
13
|
+
## Publish with Ode
|
|
14
|
+
|
|
15
|
+
Looking somewhere to publish your writing that is philosophically compatible with Prosaic? Check out [Ode](https://ode.dimwit.me/). You can also go to the [GitHub](https://github.com/DeepanshKhurana/ode/) directly.
|
|
16
|
+
|
|
17
|
+
> Ode is for writers who want to publish in an aesthetically pleasing website, ignoring the bells and whistles of the modern internet. It is opinionated, minimal, and easy to use, guided by an [Ethos](https://docs.ode.dimwit.me/ethos) that prioritizes the craft of writing and the joy of reading over metrics and engagement.
|
|
18
|
+
|
|
19
|
+
## Screenshots
|
|
20
|
+
|
|
21
|
+
| | |
|
|
22
|
+
|---|---|
|
|
23
|
+
|  |  |
|
|
24
|
+
|  |  |
|
|
25
|
+
|  |  |
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Install (requires Python 3.11+)
|
|
31
|
+
pipx install prosaic
|
|
32
|
+
|
|
33
|
+
# Run (first launch runs setup wizard)
|
|
34
|
+
prosaic
|
|
35
|
+
|
|
36
|
+
# Re-run setup wizard anytime
|
|
37
|
+
prosaic --setup
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Markdown-first**: Live outline, word counting
|
|
43
|
+
- **Focus mode**: Hide everything except your writing
|
|
44
|
+
- **Reader mode**: Distraction-free reading
|
|
45
|
+
- **Continue writing**: Resume your last edited document
|
|
46
|
+
- **Daily metrics**: Track words and characters written each day
|
|
47
|
+
- **Git-ready**: Archive is Git-initialized for versioning
|
|
48
|
+
|
|
49
|
+
## Keybindings
|
|
50
|
+
|
|
51
|
+
| Category | Key | Action |
|
|
52
|
+
|----------|-----|--------|
|
|
53
|
+
| Dashboard | `c` | Continue writing (if last file exists) |
|
|
54
|
+
| Dashboard | `p` | Write a piece |
|
|
55
|
+
| Dashboard | `b` | Work on a book |
|
|
56
|
+
| Dashboard | `n` | Add a note |
|
|
57
|
+
| Dashboard | `r` | Read notes |
|
|
58
|
+
| Dashboard | `f` | Find files |
|
|
59
|
+
| Dashboard | `?` | Help |
|
|
60
|
+
| Dashboard | `q` | Quit |
|
|
61
|
+
| Editor | `Ctrl+e` | Toggle file tree |
|
|
62
|
+
| Editor | `Ctrl+o` | Toggle outline |
|
|
63
|
+
| Editor | `Ctrl+s` | Save |
|
|
64
|
+
| Editor | `Ctrl+q` | Go home |
|
|
65
|
+
| Editor | `F5` | Focus mode |
|
|
66
|
+
| Editor | `F6` | Reader mode |
|
|
67
|
+
| Writing | `Ctrl+z` | Undo |
|
|
68
|
+
| Writing | `Ctrl+y` | Redo |
|
|
69
|
+
| Writing | `Ctrl+x` | Cut |
|
|
70
|
+
| Writing | `Ctrl+c` | Copy |
|
|
71
|
+
| Writing | `Ctrl+v` | Paste |
|
|
72
|
+
| Writing | `Ctrl+a` | Select all |
|
|
73
|
+
|
|
74
|
+
## Themes
|
|
75
|
+
|
|
76
|
+
- **Prosaic Light** (default): Warm white background with brick accents
|
|
77
|
+
- **Prosaic Dark**: Deep charcoal with warm tan accents
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Light mode (default)
|
|
81
|
+
prosaic
|
|
82
|
+
|
|
83
|
+
# Dark mode
|
|
84
|
+
prosaic --dark
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
Config location (in order of priority):
|
|
90
|
+
1. `PROSAIC_CONFIG_DIR` env var (explicit override)
|
|
91
|
+
2. `$XDG_CONFIG_HOME/prosaic/` (Linux standard)
|
|
92
|
+
3. `~/.config/prosaic/` (default)
|
|
93
|
+
|
|
94
|
+
Override with environment variable:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
PROSAIC_CONFIG_DIR=~/custom/path prosaic
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Git Integration
|
|
101
|
+
|
|
102
|
+
If your chosen archive directory already contains a git repository, the wizard will:
|
|
103
|
+
|
|
104
|
+
- Detect the existing `.git` directory
|
|
105
|
+
- Inherit the repository (no re-initialization)
|
|
106
|
+
- Read the remote URL if configured
|
|
107
|
+
- Prompt for a remote URL if none exists
|
|
108
|
+
- Store this info in `settings.json`
|
|
109
|
+
|
|
110
|
+
Example `settings.json`:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"setup_complete": true,
|
|
115
|
+
"archive_dir": "/Users/you/Prosaic",
|
|
116
|
+
"init_git": true,
|
|
117
|
+
"git_remote": "git@github.com:you/writing.git",
|
|
118
|
+
"git_inherited": true,
|
|
119
|
+
"last_file": "/Users/you/Prosaic/pieces/2026-02-21-example.md"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Archive Structure
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
~/Prosaic/ # Default archive (configurable)
|
|
127
|
+
pieces/ # Pieces with preloaded markdown frontmatter
|
|
128
|
+
books/ # Long-form projects with Outline already open
|
|
129
|
+
notes.md # Quick notes with auto date headers
|
|
130
|
+
metrics.json # Daily statistics for archival and display
|
|
131
|
+
.git/ # Version control
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Entry point for Prosaic."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from textual.app import App
|
|
7
|
+
from textual.binding import Binding
|
|
8
|
+
|
|
9
|
+
from prosaic.app import HelpScreen, NewBookModal, NewPieceModal
|
|
10
|
+
from prosaic.config import (
|
|
11
|
+
ensure_workspace,
|
|
12
|
+
get_notes_path,
|
|
13
|
+
get_workspace_dir,
|
|
14
|
+
save_config,
|
|
15
|
+
set_last_file,
|
|
16
|
+
)
|
|
17
|
+
from prosaic.core.metrics import MetricsTracker
|
|
18
|
+
from prosaic.screens import DashboardScreen, EditorScreen
|
|
19
|
+
from prosaic.themes import PROSAIC_DARK_CSS, PROSAIC_LIGHT_CSS
|
|
20
|
+
from prosaic.widgets import SpellCheckTextArea
|
|
21
|
+
from prosaic.wizard import needs_setup, run_setup, setup_workspace
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ProsaicApp(App):
|
|
25
|
+
"""Main Prosaic application."""
|
|
26
|
+
|
|
27
|
+
TITLE = "prosaic"
|
|
28
|
+
CSS = PROSAIC_LIGHT_CSS
|
|
29
|
+
BINDINGS = [
|
|
30
|
+
Binding("ctrl+q", "smart_quit", "quit", show=False, priority=True),
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
light_mode: bool = True,
|
|
36
|
+
initial_file: Path | None = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
super().__init__()
|
|
39
|
+
self.light_mode = light_mode
|
|
40
|
+
self.initial_file = initial_file
|
|
41
|
+
self.notes_path = get_notes_path()
|
|
42
|
+
ProsaicApp.CSS = PROSAIC_LIGHT_CSS if light_mode else PROSAIC_DARK_CSS
|
|
43
|
+
|
|
44
|
+
def on_mount(self) -> None:
|
|
45
|
+
ensure_workspace()
|
|
46
|
+
self.metrics = MetricsTracker(get_workspace_dir())
|
|
47
|
+
self.install_screen(DashboardScreen(self.metrics), name="dashboard")
|
|
48
|
+
|
|
49
|
+
if self.initial_file:
|
|
50
|
+
self._open_editor(self.initial_file)
|
|
51
|
+
else:
|
|
52
|
+
self.push_screen("dashboard")
|
|
53
|
+
|
|
54
|
+
def _open_editor(self, file_path: Path | None = None, show_all_panes: bool = False) -> None:
|
|
55
|
+
if file_path:
|
|
56
|
+
set_last_file(file_path)
|
|
57
|
+
|
|
58
|
+
self.push_screen(
|
|
59
|
+
EditorScreen(
|
|
60
|
+
self.metrics,
|
|
61
|
+
initial_file=file_path,
|
|
62
|
+
light_mode=self.light_mode,
|
|
63
|
+
show_all_panes=show_all_panes,
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def _open_notes(self) -> None:
|
|
68
|
+
self.push_screen(
|
|
69
|
+
EditorScreen(
|
|
70
|
+
self.metrics,
|
|
71
|
+
initial_file=self.notes_path,
|
|
72
|
+
light_mode=self.light_mode,
|
|
73
|
+
add_note=True,
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def _open_notes_readonly(self) -> None:
|
|
78
|
+
self.push_screen(
|
|
79
|
+
EditorScreen(
|
|
80
|
+
self.metrics,
|
|
81
|
+
initial_file=self.notes_path,
|
|
82
|
+
light_mode=self.light_mode,
|
|
83
|
+
reader_mode_initial=True,
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def _handle_new_piece(self, result: Path | None) -> None:
|
|
88
|
+
if result:
|
|
89
|
+
self._open_editor(result)
|
|
90
|
+
|
|
91
|
+
def _handle_new_book(self, result: Path | None) -> None:
|
|
92
|
+
if result:
|
|
93
|
+
self._open_editor(result)
|
|
94
|
+
|
|
95
|
+
def action_new_piece(self) -> None:
|
|
96
|
+
self.push_screen(NewPieceModal(), callback=self._handle_new_piece)
|
|
97
|
+
|
|
98
|
+
def action_new_book(self) -> None:
|
|
99
|
+
self.push_screen(NewBookModal(), callback=self._handle_new_book)
|
|
100
|
+
|
|
101
|
+
def toggle_theme(self) -> None:
|
|
102
|
+
self.light_mode = not self.light_mode
|
|
103
|
+
ProsaicApp.CSS = PROSAIC_LIGHT_CSS if self.light_mode else PROSAIC_DARK_CSS
|
|
104
|
+
self.refresh_css(animate=False)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
screen = self.screen
|
|
108
|
+
if isinstance(screen, EditorScreen):
|
|
109
|
+
ta = screen.query_one("#editor", SpellCheckTextArea)
|
|
110
|
+
ta.theme = "prosaic_light" if self.light_mode else "prosaic_dark"
|
|
111
|
+
ta._build_highlight_map()
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
async def action_quit(self) -> None:
|
|
116
|
+
self.exit()
|
|
117
|
+
|
|
118
|
+
def action_smart_quit(self) -> None:
|
|
119
|
+
screen = self.screen
|
|
120
|
+
if isinstance(screen, EditorScreen):
|
|
121
|
+
screen.action_go_home()
|
|
122
|
+
elif isinstance(screen, DashboardScreen):
|
|
123
|
+
self.exit()
|
|
124
|
+
elif len(self.screen_stack) > 1:
|
|
125
|
+
self.pop_screen()
|
|
126
|
+
else:
|
|
127
|
+
self.exit()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@click.command()
|
|
131
|
+
@click.option("--light/--dark", default=True, help="Use light or dark theme")
|
|
132
|
+
@click.option("--setup", is_flag=True, help="Run setup wizard again")
|
|
133
|
+
@click.argument("file", required=False, type=click.Path())
|
|
134
|
+
def main(light: bool, setup: bool, file: str | None) -> None:
|
|
135
|
+
"""Prosaic - A writer-first terminal writing app."""
|
|
136
|
+
if setup or needs_setup():
|
|
137
|
+
config = run_setup()
|
|
138
|
+
save_config(config)
|
|
139
|
+
setup_workspace(config)
|
|
140
|
+
|
|
141
|
+
app = ProsaicApp(
|
|
142
|
+
light_mode=light,
|
|
143
|
+
initial_file=Path(file) if file else None,
|
|
144
|
+
)
|
|
145
|
+
app.run()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|