mirror of
https://github.com/1j01/textual-paint.git
synced 2024-12-22 14:21:33 +03:00
Extract argument parsing to a file
This commit is contained in:
parent
d471e92855
commit
ad83dee949
76
src/textual_paint/args.py
Normal file
76
src/textual_paint/args.py
Normal file
@ -0,0 +1,76 @@
|
||||
"""Command line arguments for the app."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
from .__init__ import __version__
|
||||
|
||||
parser = argparse.ArgumentParser(description='Paint in the terminal.', usage='%(prog)s [options] [filename]', prog="textual-paint")
|
||||
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
|
||||
parser.add_argument('--theme', default='light', help='Theme to use, either "light" or "dark"', choices=['light', 'dark'])
|
||||
parser.add_argument('--language', default='en', help='Language to use', choices=['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'])
|
||||
parser.add_argument('--ascii-only-icons', action='store_true', help='Use only ASCII characters for tool icons, no emoji or other Unicode symbols')
|
||||
parser.add_argument('--ascii-only', action='store_true', help='Use only ASCII characters for the entire UI, for use in older terminals. Implies --ascii-only-icons')
|
||||
parser.add_argument('--backup-folder', default=None, metavar="FOLDER", help='Folder to save backups to. By default a backup is saved alongside the edited file.')
|
||||
|
||||
# TODO: hide development options from help? there's quite a few of them now
|
||||
parser.add_argument('--inspect-layout', action='store_true', help='Enables DOM inspector (F12) and middle click highlight, for development')
|
||||
# This flag is for development, because it's very confusing
|
||||
# to see the error message from the previous run,
|
||||
# when a problem is actually solved.
|
||||
# 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 outdated 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('--recode-samples', action='store_true', help='Open and save each file in samples/, for testing')
|
||||
|
||||
parser.add_argument('filename', nargs='?', default=None, help='Path to a file to open. File will be created if it doesn\'t exist.')
|
||||
|
||||
def update_cli_help_on_readme():
|
||||
"""Update the readme with the current CLI usage info"""
|
||||
readme_help_start = re.compile(r"```\n.*--help\n")
|
||||
readme_help_end = re.compile(r"```")
|
||||
readme_file_path = os.path.join(os.path.dirname(__file__), "../../README.md")
|
||||
with open(readme_file_path, "r+", encoding="utf-8") as f:
|
||||
# By default, argparse uses the terminal width for formatting help text,
|
||||
# even when using format_help() to get a string.
|
||||
# The only way to override that is to override the formatter_class.
|
||||
# This is hacky, but it seems like the simplest way to fix the width
|
||||
# without creating a separate ArgumentParser, and without breaking the wrapping for --help.
|
||||
# This lambda works because python uses the same syntax for construction and function calls,
|
||||
# so formatter_class doesn't need to be an actual class.
|
||||
# See: https://stackoverflow.com/questions/44333577/explain-lambda-argparse-helpformatterprog-width
|
||||
width = 80
|
||||
old_formatter_class = parser.formatter_class
|
||||
parser.formatter_class = lambda prog: argparse.HelpFormatter(prog, width=width)
|
||||
help_text = parser.format_help()
|
||||
parser.formatter_class = old_formatter_class
|
||||
|
||||
md = f.read()
|
||||
start_match = readme_help_start.search(md)
|
||||
if start_match is None:
|
||||
raise Exception("Couldn't find help section in readme")
|
||||
start = start_match.end()
|
||||
end_match = readme_help_end.search(md, start)
|
||||
if end_match is None:
|
||||
raise Exception("Couldn't find end of help section in readme")
|
||||
end = end_match.start()
|
||||
md = md[:start] + help_text + md[end:]
|
||||
f.seek(0)
|
||||
f.write(md)
|
||||
f.truncate()
|
||||
# Manually disabled for release.
|
||||
# TODO: disable for release builds, while keeping it automatic during development.
|
||||
# (I could make this another dev flag, but I like the idea of it being automatic.)
|
||||
# (Maybe a pre-commit hook would be ideal, if it's worth the complexity.)
|
||||
# update_cli_help_on_readme()
|
||||
|
||||
args = parser.parse_args()
|
||||
"""Parsed command line arguments."""
|
||||
|
||||
def get_help_text() -> str:
|
||||
"""Get the help text for the command line arguments."""
|
||||
return parser.format_help()
|
||||
|
||||
__all__ = ["args", "get_help_text"]
|
@ -7,7 +7,6 @@ import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shlex
|
||||
import argparse
|
||||
import asyncio
|
||||
from enum import Enum
|
||||
from random import randint, random
|
||||
@ -57,6 +56,7 @@ from .localization.i18n import get as _, load_language, remove_hotkey
|
||||
from .rasterize_ansi_art import rasterize
|
||||
from .wallpaper import get_config_dir, set_wallpaper
|
||||
from .auto_restart import restart_on_changes, restart_program
|
||||
from .args import args, get_help_text
|
||||
|
||||
from .__init__ import __version__
|
||||
|
||||
@ -69,72 +69,10 @@ DEBUG_SVG_LOADING = False # writes debug.svg when flexible character grid loader
|
||||
# ICNS is disabled because it only supports a limited set of sizes.
|
||||
SAVE_DISABLED_FORMATS = ["JPEG", "ICNS"]
|
||||
|
||||
# Command line arguments
|
||||
parser = argparse.ArgumentParser(description='Paint in the terminal.', usage='%(prog)s [options] [filename]', prog="textual-paint")
|
||||
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')
|
||||
parser.add_argument('--theme', default='light', help='Theme to use, either "light" or "dark"', choices=['light', 'dark'])
|
||||
parser.add_argument('--language', default='en', help='Language to use', choices=['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'])
|
||||
parser.add_argument('--ascii-only-icons', action='store_true', help='Use only ASCII characters for tool icons, no emoji or other Unicode symbols')
|
||||
parser.add_argument('--ascii-only', action='store_true', help='Use only ASCII characters for the entire UI, for use in older terminals. Implies --ascii-only-icons')
|
||||
parser.add_argument('--backup-folder', default=None, metavar="FOLDER", help='Folder to save backups to. By default a backup is saved alongside the edited file.')
|
||||
|
||||
# TODO: hide development options from help? there's quite a few of them now
|
||||
parser.add_argument('--inspect-layout', action='store_true', help='Enables DOM inspector (F12) and middle click highlight, for development')
|
||||
# This flag is for development, because it's very confusing
|
||||
# to see the error message from the previous run,
|
||||
# when a problem is actually solved.
|
||||
# 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 outdated 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('--recode-samples', action='store_true', help='Open and save each file in samples/, for testing')
|
||||
|
||||
parser.add_argument('filename', nargs='?', default=None, help='Path to a file to open. File will be created if it doesn\'t exist.')
|
||||
|
||||
def update_cli_help_on_readme():
|
||||
"""Update the readme with the current CLI usage info"""
|
||||
readme_help_start = re.compile(r"```\n.*--help\n")
|
||||
readme_help_end = re.compile(r"```")
|
||||
readme_file_path = os.path.join(os.path.dirname(__file__), "../../README.md")
|
||||
with open(readme_file_path, "r+", encoding="utf-8") as f:
|
||||
# By default, argparse uses the terminal width for formatting help text,
|
||||
# even when using format_help() to get a string.
|
||||
# The only way to override that is to override the formatter_class.
|
||||
# This is hacky, but it seems like the simplest way to fix the width
|
||||
# without creating a separate ArgumentParser, and without breaking the wrapping for --help.
|
||||
# This lambda works because python uses the same syntax for construction and function calls,
|
||||
# so formatter_class doesn't need to be an actual class.
|
||||
# See: https://stackoverflow.com/questions/44333577/explain-lambda-argparse-helpformatterprog-width
|
||||
width = 80
|
||||
old_formatter_class = parser.formatter_class
|
||||
parser.formatter_class = lambda prog: argparse.HelpFormatter(prog, width=width)
|
||||
help_text = parser.format_help()
|
||||
parser.formatter_class = old_formatter_class
|
||||
|
||||
md = f.read()
|
||||
start_match = readme_help_start.search(md)
|
||||
if start_match is None:
|
||||
raise Exception("Couldn't find help section in readme")
|
||||
start = start_match.end()
|
||||
end_match = readme_help_end.search(md, start)
|
||||
if end_match is None:
|
||||
raise Exception("Couldn't find end of help section in readme")
|
||||
end = end_match.start()
|
||||
md = md[:start] + help_text + md[end:]
|
||||
f.seek(0)
|
||||
f.write(md)
|
||||
f.truncate()
|
||||
# Manually disabled for release.
|
||||
# TODO: disable for release builds, while keeping it automatic during development.
|
||||
# (I could make this another dev flag, but I like the idea of it being automatic.)
|
||||
# (Maybe a pre-commit hook would be ideal, if it's worth the complexity.)
|
||||
# update_cli_help_on_readme()
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Most arguments are handled at the end of the file,
|
||||
# but it may be important to do this one early.
|
||||
load_language(args.language)
|
||||
|
||||
# Most arguments are handled at the end of the file.
|
||||
|
||||
class MetaGlyphFont:
|
||||
def __init__(self, file_path: str, width: int, height: int, covered_characters: str):
|
||||
@ -4244,7 +4182,7 @@ Columns: {len(palette) // 2}
|
||||
allow_maximize=True,
|
||||
allow_minimize=True,
|
||||
)
|
||||
help_text = parser.format_help()
|
||||
help_text = get_help_text()
|
||||
window.content.mount(Container(Static(help_text, markup=False), classes="help_text_container"))
|
||||
window.content.mount(Button(_("OK"), classes="ok submit"))
|
||||
self.mount(window)
|
||||
@ -5299,9 +5237,6 @@ Columns: {len(palette) // 2}
|
||||
if args.ascii_only:
|
||||
args.ascii_only_icons = True
|
||||
|
||||
import textual_paint.windows
|
||||
textual_paint.windows.ascii_only = True
|
||||
|
||||
from .ascii_borders import force_ascii_borders
|
||||
force_ascii_borders()
|
||||
|
||||
|
@ -14,9 +14,7 @@ from textual.containers import Container, Horizontal, Vertical
|
||||
from textual.css.query import NoMatches
|
||||
|
||||
from .localization.i18n import get as _
|
||||
|
||||
ascii_only = False
|
||||
"""This is overwritten in paint.py when --ascii-only is passed."""
|
||||
from .args import args
|
||||
|
||||
class WindowTitleBar(Container):
|
||||
"""A title bar widget."""
|
||||
@ -597,7 +595,7 @@ warning_icon_markup_ascii_dark_mode = """[#ffff00]
|
||||
[/]"""
|
||||
|
||||
def get_warning_icon() -> Static:
|
||||
markup = warning_icon_markup_ascii if ascii_only else warning_icon_markup_unicode
|
||||
markup = warning_icon_markup_ascii if args.ascii_only else warning_icon_markup_unicode
|
||||
# TODO: Use warning_icon_markup_ascii_dark_mode for a less blocky looking outline in dark mode.
|
||||
return Static(markup, classes="warning_icon message_box_icon")
|
||||
|
||||
@ -664,7 +662,7 @@ question_icon_console_markup_ascii = """
|
||||
question_icon_console_markup_ascii = question_icon_console_markup_ascii.replace(" on rgb(128,128,128)", "")
|
||||
|
||||
def get_question_icon() -> Static:
|
||||
markup = question_icon_console_markup_ascii if ascii_only else question_icon_console_markup
|
||||
markup = question_icon_console_markup_ascii if args.ascii_only else question_icon_console_markup
|
||||
return Static(markup, classes="question_icon message_box_icon")
|
||||
|
||||
|
||||
@ -691,7 +689,7 @@ paint_icon_console_markup_ascii = """
|
||||
paint_icon_console_markup_ascii = paint_icon_console_markup_ascii.replace(" on rgb(255,0,255)", "")
|
||||
|
||||
def get_paint_icon() -> Static:
|
||||
markup = paint_icon_console_markup_ascii if ascii_only else paint_icon_console_markup
|
||||
markup = paint_icon_console_markup_ascii if args.ascii_only else paint_icon_console_markup
|
||||
return Static(markup, classes="paint_icon message_box_icon")
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user