mirror of
https://github.com/1j01/textual-paint.git
synced 2024-12-25 15:53:12 +03:00
Restart the app on changes
This commit is contained in:
parent
adcaed47cd
commit
140ff15ff1
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
@ -27,6 +27,15 @@
|
||||
"args": ["run", "--dev", "paint.py --clear-screen --inspect-layout LICENSE.txt"],
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": "Debug --restart-on-changes file matching",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${userHome}/.local/bin/textual",
|
||||
"args": ["run", "--dev", "paint.py --clear-screen --restart-on-changes"],
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false
|
||||
}
|
||||
]
|
||||
}
|
22
README.md
22
README.md
@ -69,8 +69,8 @@ textual-paint
|
||||
|
||||
```
|
||||
$ python3 paint.py --help
|
||||
usage: paint.py [-h] [--theme {light,dark}] [--language {ar,cs,da,de,el,en,es,fi,fr,he,hu,it,ja,ko,nl,no,pl,pt,pt-br,ru,sk,sl,sv,tr,zh,zh-simplified}]
|
||||
[--ascii-only-icons] [--inspect-layout] [--clear-screen]
|
||||
usage: paint.py [-h] [--theme {light,dark}] [--language {ar,cs,da,de,el,en,es,fi,fr,he,hu,it,ja,ko,nl,no,pl,pt,pt-br,ru,sk,sl,sv,tr,zh,zh-simplified}] [--ascii-only-icons]
|
||||
[--inspect-layout] [--clear-screen] [--restart-on-changes]
|
||||
[filename]
|
||||
|
||||
Paint in the terminal.
|
||||
@ -86,6 +86,7 @@ options:
|
||||
--ascii-only-icons Use only ASCII characters for tool icons
|
||||
--inspect-layout Inspect the layout with middle click, for development
|
||||
--clear-screen Clear the screen before starting; useful for development, to avoid seeing fixed errors
|
||||
--restart-on-changes Restart the app when the source code is changed, for development
|
||||
```
|
||||
|
||||
### Keyboard Shortcuts
|
||||
@ -113,21 +114,30 @@ Install Textual and other dependencies:
|
||||
pip install "textual[dev]" stransi psutil
|
||||
```
|
||||
|
||||
Run via Textual's CLI for live-reloading CSS support:
|
||||
Run via Textual's CLI for live-reloading CSS support, and enable other development features:
|
||||
```bash
|
||||
textual run --dev "paint.py --clear-screen"
|
||||
textual run --dev "paint.py --clear-screen --inspect-layout --restart-on-changes"
|
||||
```
|
||||
|
||||
Or run more basically:
|
||||
```bash
|
||||
python paint.py --clear-screen
|
||||
python paint.py
|
||||
```
|
||||
|
||||
`--clear-screen` is useful for development, because it's sometimes jarring to see error messages that have actually been fixed, when exiting the program.
|
||||
|
||||
`--inspect-layout` lets you middle click to visualize the layout breakdown by labeling each widget in the hierarchy, and coloring their regions. The labels affect the layout, so you can also hold Ctrl to only colorize, and you can remember how the colors correspond to the labels.
|
||||
|
||||
`--restart-on-changes` automatically restarts the program when any Python files change. This works by the program restarting itself directly. (Programs like `modd` or `nodemon` that run your program in a subprocess don't work well with Textual's escape sequences.)
|
||||
|
||||
There are also launch tasks configured for VS Code, so you can run the program from the Run and Debug panel.
|
||||
|
||||
I tried running via `modd` to automatically reload the program when (non-CSS) files change, but it doesn't handle ANSI escape sequences well. I wonder if it would work better now with the `--clear-screen` option. (I could also look for another tool that's more part of the Python ecosystem.)
|
||||
### Update Dependencies
|
||||
|
||||
```bash
|
||||
python -m pipreqs.pipreqs --ignore .history --force
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
"llpaper",
|
||||
"modd",
|
||||
"Odhner",
|
||||
"pipreqs",
|
||||
"Playscii",
|
||||
"psutil",
|
||||
"pycache",
|
||||
|
37
paint.py
37
paint.py
@ -7,6 +7,8 @@ import asyncio
|
||||
from enum import Enum
|
||||
from random import randint, random
|
||||
from typing import List, Optional
|
||||
from watchdog.events import PatternMatchingEventHandler, FileSystemEvent, EVENT_TYPE_CLOSED, EVENT_TYPE_OPENED
|
||||
from watchdog.observers import Observer
|
||||
import stransi
|
||||
from rich.segment import Segment
|
||||
from rich.style import Style
|
||||
@ -52,6 +54,36 @@ def restart_program():
|
||||
# os.execl(python, python, *sys.argv)
|
||||
os.execl(sys.executable, *sys.orig_argv)
|
||||
|
||||
class RestartHandler(PatternMatchingEventHandler):
|
||||
"""A handler for file changes"""
|
||||
def on_any_event(self, event: FileSystemEvent):
|
||||
if event.event_type in (EVENT_TYPE_CLOSED, EVENT_TYPE_OPENED):
|
||||
# These seem like they'd just cause trouble... they're not changes, are they?
|
||||
return
|
||||
restart_program()
|
||||
|
||||
def restart_on_changes():
|
||||
"""Restarts the current program when a file is changed"""
|
||||
observer = Observer()
|
||||
observer.schedule(RestartHandler(
|
||||
# Don't need to restart on changes to .css, since Textual will reload them in --dev mode
|
||||
# Could include localization files, but I'm not actively localizing this app at this point.
|
||||
# WET: WatchDog doesn't match zero directories for **, so we have to split up any patterns that use it.
|
||||
patterns=[
|
||||
"**/*.py", "*.py"
|
||||
],
|
||||
ignore_patterns=[
|
||||
".history/**/*", ".history/*",
|
||||
".vscode/**/*", ".vscode/*",
|
||||
".git/**/*", ".git/*",
|
||||
"node_modules/**/*", "node_modules/*",
|
||||
"__pycache__/**/*", "__pycache__/*",
|
||||
"venv/**/*", "venv/*",
|
||||
],
|
||||
ignore_directories=True,
|
||||
), path='.', recursive=True)
|
||||
observer.start()
|
||||
|
||||
|
||||
# These can go away now that args are parsed up top
|
||||
ascii_only_icons = False
|
||||
@ -70,7 +102,9 @@ parser.add_argument('--inspect-layout', action='store_true', help='Inspect the l
|
||||
# There are enough ACTUAL "that should have worked!!" moments to deal with.
|
||||
# I really don't want false ones mixed in. You want to reward your brain for finding good solutions, after all.
|
||||
parser.add_argument('--clear-screen', action='store_true', help='Clear the screen before starting; useful for development, to avoid seeing fixed errors')
|
||||
parser.add_argument('--restart-on-changes', action='store_true', help='Restart the app when the source code is changed, for development')
|
||||
parser.add_argument('filename', nargs='?', default=None, help='File to open')
|
||||
|
||||
if __name__ == "<run_path>":
|
||||
# Arguments have to be passed like `textual run --dev "paint.py LICENSE.txt"`
|
||||
# so we need to look for an argument starting with "paint.py",
|
||||
@ -85,6 +119,9 @@ else:
|
||||
|
||||
load_language(args.language)
|
||||
|
||||
if args.restart_on_changes:
|
||||
restart_on_changes()
|
||||
|
||||
# Most arguments are handled at the end of the file.
|
||||
|
||||
class Tool(Enum):
|
||||
|
@ -2,3 +2,4 @@ psutil==5.9.0
|
||||
rich==13.3.4
|
||||
stransi==0.3.0
|
||||
textual==0.20.1
|
||||
watchdog==3.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user