utils.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #!/usr/bin/env python
  2. # License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
  3. import os
  4. import sys
  5. from collections.abc import Sequence
  6. from contextlib import suppress
  7. from typing import TYPE_CHECKING, Optional, cast
  8. from kitty.types import run_once
  9. from .operations import raw_mode, set_cursor_visible
  10. if TYPE_CHECKING:
  11. from kitty.options.types import Options
  12. def get_key_press(allowed: str, default: str) -> str:
  13. response = default
  14. with raw_mode():
  15. print(set_cursor_visible(False), end='', flush=True)
  16. try:
  17. while True:
  18. q = sys.stdin.buffer.read(1)
  19. if q:
  20. if q in b'\x1b\x03':
  21. break
  22. with suppress(Exception):
  23. response = q.decode('utf-8').lower()
  24. if response in allowed:
  25. break
  26. except (KeyboardInterrupt, EOFError):
  27. pass
  28. finally:
  29. print(set_cursor_visible(True), end='', flush=True)
  30. return response
  31. def format_number(val: float, max_num_of_decimals: int = 2) -> str:
  32. ans = str(val)
  33. pos = ans.find('.')
  34. if pos > -1:
  35. ans = ans[:pos + max_num_of_decimals + 1]
  36. return ans.rstrip('0').rstrip('.')
  37. def human_size(
  38. size: int, sep: str = ' ',
  39. max_num_of_decimals: int = 2,
  40. unit_list: tuple[str, ...] = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB')
  41. ) -> str:
  42. """ Convert a size in bytes into a human readable form """
  43. if size < 2:
  44. return f'{size}{sep}{unit_list[0]}'
  45. from math import log
  46. exponent = min(int(log(size, 1024)), len(unit_list) - 1)
  47. return format_number(size / 1024**exponent, max_num_of_decimals) + sep + unit_list[exponent]
  48. def kitty_opts() -> 'Options':
  49. from kitty.fast_data_types import get_options, set_options
  50. try:
  51. ans = cast(Optional['Options'], get_options())
  52. except RuntimeError:
  53. ans = None
  54. if ans is None:
  55. from kitty.cli import create_default_opts
  56. from kitty.utils import suppress_error_logging
  57. with suppress_error_logging():
  58. ans = create_default_opts()
  59. set_options(ans)
  60. return ans
  61. def set_kitty_opts(paths: Sequence[str], overrides: Sequence[str] = ()) -> 'Options':
  62. from kitty.config import load_config
  63. from kitty.fast_data_types import set_options
  64. from kitty.utils import suppress_error_logging
  65. with suppress_error_logging():
  66. opts = load_config(*paths, overrides=overrides or None)
  67. set_options(opts)
  68. return opts
  69. def report_error(msg: str = '', return_code: int = 1, print_exc: bool = False) -> None:
  70. ' Report an error also sending the overlay ready message to ensure kitten is visible '
  71. from .operations import overlay_ready
  72. print(end=overlay_ready())
  73. if msg:
  74. print(msg, file=sys.stderr)
  75. if print_exc:
  76. cls, e, tb = sys.exc_info()
  77. if e and not isinstance(e, (SystemExit, KeyboardInterrupt)):
  78. import traceback
  79. traceback.print_exc()
  80. with suppress(KeyboardInterrupt, EOFError):
  81. input('Press Enter to quit')
  82. raise SystemExit(return_code)
  83. def report_unhandled_error(msg: str = '') -> None:
  84. ' Report an unhandled exception with the overlay ready message '
  85. return report_error(msg, print_exc=True)
  86. @run_once
  87. def running_in_tmux() -> str:
  88. socket = os.environ.get('TMUX')
  89. if not socket:
  90. return ''
  91. parts = socket.split(',')
  92. if len(parts) < 2:
  93. return ''
  94. try:
  95. if not os.access(parts[0], os.R_OK | os.W_OK):
  96. return ''
  97. except OSError:
  98. return ''
  99. from kitty.child import cmdline_of_pid
  100. c = cmdline_of_pid(int(parts[1]))
  101. if not c:
  102. return ''
  103. exe = os.path.basename(c[0])
  104. if exe.lower() == 'tmux':
  105. return exe
  106. return ''