from itertools import repeat from kitty.cli import parse_args from kitty.cli_stub import HintsCLIOptions from kitty.fast_data_types import set_clipboard_string from kitty.key_encoding import key_defs as K, backspace_key, enter_key from kitty.utils import screen_size_function from ..tui.handler import Handler, result_handler from ..tui.loop import Loop from ..tui.operations import faint, styled URL_PREFIXES = 'http https file ftp'.split() DEFAULT_HINT_ALPHABET = string.digits + string.ascii_lowercase DEFAULT_REGEX = r'(?m)^\s*(.+)\s*$' screen_size = screen_size_function() ESCAPE = K['ESCAPE'] class Mark: __slots__ = ('index', 'start', 'end', 'text', 'groupdict') def __init__(self, index, start, end, text, groupdict): self.index, self.start, self.end = index, start, end self.text = text self.groupdict = groupdict @lru_cache(maxsize=2048) def encode_hint(num, alphabet):
def parse_input(text: str) -> str: try: cols = int(os.environ['OVERLAID_WINDOW_COLS']) except KeyError: cols = screen_size_function()().cols return convert_text(text, cols)
def main(args=sys.argv): global screen_size args, items = parse_args(args[1:], options_spec, usage, help_text, '{} +kitten icat'.format(appname)) if args.print_window_size: screen_size_function.ans = None with open(os.ctermid()) as tty: ss = screen_size_function(tty)() print('{}x{}'.format(ss.width, ss.height), end='') raise SystemExit(0) if not sys.stdout.isatty(): sys.stdout = open(os.ctermid(), 'w') screen_size = screen_size_function() signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True)) if screen_size().width == 0: if args.detect_support: raise SystemExit(1) raise SystemExit( 'Terminal does not support reporting screen sizes via the TIOCGWINSZ ioctl' ) try: args.place = parse_place(args.place) except Exception: raise SystemExit('Not a valid place specification: {}'.format( args.place)) if args.detect_support: if not detect_support(wait_for=args.detection_timeout, silent=True): raise SystemExit(1) print('file' if detect_support.has_files else 'stream', end='', file=sys.stderr) return if args.transfer_mode == 'detect': if not detect_support(wait_for=args.detection_timeout): raise SystemExit( 'This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it' ) else: detect_support.has_files = args.transfer_mode == 'file' errors = [] if args.clear: sys.stdout.buffer.write(clear_images_on_screen(delete_data=True)) if not items: return if not items: raise SystemExit('You must specify at least one file to cat') if args.place: if len(items) > 1 or os.path.isdir(items[0]): raise SystemExit( 'The --place option can only be used with a single image') sys.stdout.buffer.write(b'\0337') # save cursor for item in items: try: if os.path.isdir(item): for x in scan(item): process(item, args) else: process(item, args) except NoImageMagick as e: raise SystemExit(str(e)) except ConvertFailed as e: raise SystemExit(str(e)) except OpenFailed as e: errors.append(e) if args.place: sys.stdout.buffer.write(b'\0338') # restore cursor if not errors: return for err in errors: print(err, file=sys.stderr) raise SystemExit(1)
def __call__(self, seq: OptionSpecSeq, usage: Optional[str], message: Optional[str], appname: str) -> None: from kitty.utils import screen_size_function screen_size = screen_size_function() try: linesz = min(screen_size().cols, 76) except OSError: linesz = 76 blocks: List[str] = [] a = blocks.append def wa(text: str, indent: int = 0, leading_indent: Optional[int] = None) -> None: if leading_indent is None: leading_indent = indent j = '\n' + (' ' * indent) lines: List[str] = [] for ln in text.splitlines(): if ln: lines.extend(wrap(ln, limit=linesz - indent)) else: lines.append('') a((' ' * leading_indent) + j.join(lines)) usage = '[program-to-run ...]' if usage is None else usage optstring = '[options] ' if seq else '' a('{}: {} {}{}'.format(title('Usage'), bold(yellow(appname)), optstring, usage)) a('') message = message or default_msg wa(prettify(message)) a('') if seq: a('{}:'.format(title('Options'))) for opt in seq: if isinstance(opt, str): a(f'{title(opt)}:') continue help_text = opt['help'] if help_text == '!': continue # hidden option a(' ' + ', '.join(map(green, sorted(opt['aliases'])))) if not opt.get('type', '').startswith('bool-'): blocks[-1] += '={}'.format(italic(opt['dest'].upper())) if opt.get('help'): defval = opt.get('default') t = help_text.replace('%default', str(defval)) wa(prettify(t.strip()), indent=4) if defval is not None: wa(f'Default: {defval}', indent=4) if opt.get('choices'): wa('Choices: {}'.format(', '.join(opt['choices'])), indent=4) a('') text = '\n'.join(blocks) + '\n\n' + version() if print_help_for_seq.allow_pager and sys.stdout.isatty(): import subprocess p = subprocess.Popen(['less', '-isRXF'], stdin=subprocess.PIPE) try: p.communicate(text.encode('utf-8')) except KeyboardInterrupt: raise SystemExit(1) raise SystemExit(p.wait()) else: print(text)
def main(args: List[str] = sys.argv) -> None: global can_transfer_with_files cli_opts, items_ = parse_args(args[1:], options_spec, usage, help_text, '{} +kitten icat'.format(appname), result_class=IcatCLIOptions) items: List[Union[str, bytes]] = list(items_) if cli_opts.print_window_size: screen_size_function.cache_clear() with open(os.ctermid()) as tty: ss = screen_size_function(tty)() print('{}x{}'.format(ss.width, ss.height), end='') raise SystemExit(0) if not sys.stdout.isatty(): sys.stdout = open(os.ctermid(), 'w') stdin_data = None if cli_opts.stdin == 'yes' or (not sys.stdin.isatty() and cli_opts.stdin == 'detect'): stdin_data = sys.stdin.buffer.read() if stdin_data: items.insert(0, stdin_data) sys.stdin.close() sys.stdin = open(os.ctermid(), 'r') screen_size = get_screen_size_function() signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True)) if screen_size().width == 0: if cli_opts.detect_support: raise SystemExit(1) raise SystemExit( 'Terminal does not support reporting screen sizes via the TIOCGWINSZ ioctl' ) parsed_opts = ParsedOpts() if cli_opts.place: try: parsed_opts.place = parse_place(cli_opts.place) except Exception: raise SystemExit('Not a valid place specification: {}'.format(cli_opts.place)) try: parsed_opts.z_index = parse_z_index(cli_opts.z_index) except Exception: raise SystemExit('Not a valid z-index specification: {}'.format(cli_opts.z_index)) if cli_opts.detect_support: if not detect_support(wait_for=cli_opts.detection_timeout, silent=True): raise SystemExit(1) print('file' if can_transfer_with_files else 'stream', end='', file=sys.stderr) return if cli_opts.transfer_mode == 'detect': if not detect_support(wait_for=cli_opts.detection_timeout, silent=cli_opts.silent): raise SystemExit('This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it') else: can_transfer_with_files = cli_opts.transfer_mode == 'file' errors = [] if cli_opts.clear: sys.stdout.write(clear_images_on_screen(delete_data=True)) if not items: return if not items: raise SystemExit('You must specify at least one file to cat') if parsed_opts.place: if len(items) > 1 or (isinstance(items[0], str) and os.path.isdir(items[0])): raise SystemExit(f'The --place option can only be used with a single image, not {items}') sys.stdout.buffer.write(b'\0337') # save cursor url_pat = re.compile(r'(?:https?|ftp)://', flags=re.I) for item in items: try: process_single_item(item, cli_opts, parsed_opts, url_pat) except NoImageMagick as e: raise SystemExit(str(e)) except ConvertFailed as e: raise SystemExit(str(e)) except OpenFailed as e: errors.append(e) if parsed_opts.place: sys.stdout.buffer.write(b'\0338') # restore cursor if errors: for err in errors: print(err, file=sys.stderr) if cli_opts.hold: with open(os.ctermid()) as tty: with raw_mode(tty.fileno()): tty.buffer.read(1) raise SystemExit(1 if errors else 0)
def get_screen_size_function() -> ScreenSizeGetter: global screen_size if screen_size is None: screen_size = screen_size_function() return screen_size