main.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/env python3
  2. from __future__ import annotations
  3. import argparse
  4. import json
  5. from dataclasses import dataclass
  6. from pathlib import Path
  7. from typing import Iterable
  8. from .color_util import AnsiMode, printc, color
  9. from .neofetch_util import run_neofetch
  10. from .presets import PRESETS, ColorProfile
  11. from .serializer import json_stringify
  12. CONFIG_PATH = Path.home() / '.config/hyfetch.json'
  13. VERSION = '1.0.7'
  14. @dataclass
  15. class Config:
  16. preset: str
  17. mode: AnsiMode
  18. def save(self):
  19. CONFIG_PATH.parent.mkdir(exist_ok=True, parents=True)
  20. CONFIG_PATH.write_text(json_stringify(self), 'utf-8')
  21. def check_config() -> Config:
  22. """
  23. Check if the configuration exists. Return the config object if it exists. If not, call the
  24. config creator
  25. TODO: Config path param
  26. :return: Config object
  27. """
  28. if CONFIG_PATH.is_file():
  29. return Config(**json.loads(CONFIG_PATH.read_text('utf-8')))
  30. return create_config()
  31. def literal_input(prompt: str, options: Iterable[str], default: str) -> str:
  32. """
  33. Ask the user to provide an input among a list of options
  34. :param prompt: Input prompt
  35. :param options: Options
  36. :param default: Default option
  37. :return: Selection
  38. """
  39. options = list(options)
  40. lows = [o.lower() for o in options]
  41. op_text = '|'.join([f'&l&n{o}&r' if o == default else o for o in options])
  42. printc(f'{prompt} ({op_text})')
  43. selection = input('> ') or default
  44. while not selection.lower() in lows:
  45. print(f'Invalid selection! {selection} is not one of {"|".join(options)}')
  46. selection = input('> ') or default
  47. print()
  48. return options[lows.index(selection)]
  49. def center_text(txt: str, spaces: int) -> str:
  50. """
  51. Put the text in the center in a defined space
  52. >>> center_text('meow', 9)
  53. ' meow '
  54. :param txt: Text
  55. :param spaces: Total space of the text
  56. :return: Text with length spaces
  57. """
  58. spaces -= len(txt)
  59. if spaces % 2 == 1:
  60. spaces -= 1
  61. txt += ' '
  62. while spaces > 0:
  63. spaces -= 2
  64. txt = f' {txt} '
  65. return txt
  66. def create_config() -> Config:
  67. """
  68. Create config interactively
  69. :return: Config object (automatically stored)
  70. """
  71. # Select color system
  72. # TODO: Demo of each color system
  73. color_system = literal_input('Which &acolor &bsystem &rdo you want to use?',
  74. ['8bit', 'rgb'], 'rgb')
  75. # Print preset
  76. print('Available presets:\n')
  77. spacing = max(max(len(k) for k in PRESETS.keys()), 30)
  78. flags = []
  79. for name, preset in PRESETS.items():
  80. flags.append([preset.color_text(' ' * spacing, foreground=False),
  81. '&0' + preset.color_text(center_text(name, spacing), foreground=False),
  82. preset.color_text(' ' * spacing, foreground=False)])
  83. flags_per_row = 3
  84. while flags:
  85. current = flags[:flags_per_row]
  86. flags = flags[flags_per_row:]
  87. for line in range(len(current[0])):
  88. printc(' '.join(flag[line] for flag in current))
  89. print()
  90. print()
  91. tmp = PRESETS['rainbow'].color_text('preset')
  92. preset = literal_input(f'Which {tmp} do you want to use?', PRESETS.keys(), 'rainbow')
  93. # Create config
  94. c = Config(preset, color_system)
  95. # Save config
  96. save = literal_input(f'Save config?', ['y', 'n'], 'y')
  97. if save == 'y':
  98. c.save()
  99. return c
  100. def run():
  101. # Create CLI
  102. hyfetch = color('&b&lhy&f&lfetch&r')
  103. parser = argparse.ArgumentParser(description=color(f'{hyfetch} - neofetch with flags <3'))
  104. parser.add_argument('-c', '--config', action='store_true', help=color(f'Configure {hyfetch}'))
  105. parser.add_argument('-p', '--preset', help=f'Use preset', choices=PRESETS.keys())
  106. parser.add_argument('-m', '--mode', help=f'Color mode', choices=['8bit', 'rgb'])
  107. parser.add_argument('--c-scale', dest='scale', help=f'Lighten colors by a multiplier', type=float)
  108. parser.add_argument('--c-set-l', dest='light', help=f'Set lightness value of the colors', type=float)
  109. parser.add_argument('-V', '--version', dest='version', action='store_true', help=f'Check version')
  110. args = parser.parse_args()
  111. if args.version:
  112. print(f'Version is {VERSION}')
  113. return
  114. # Load config
  115. config = check_config()
  116. # Reset config
  117. if args.config:
  118. config = create_config()
  119. # Param overwrite config
  120. if args.preset:
  121. config.preset = args.preset
  122. if args.mode:
  123. config.mode = args.mode
  124. preset = PRESETS.get(config.preset)
  125. # Lighten
  126. if args.scale:
  127. preset = ColorProfile([c.lighten(args.scale) for c in preset.colors])
  128. if args.light:
  129. preset = ColorProfile([c.set_light(args.light) for c in preset.colors])
  130. # Run
  131. run_neofetch(preset, config.mode)