utils.py 3.8 KB

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