Compare commits

..

23 Commits

Author SHA1 Message Date
Kovid Goyal
b65119b8a9 Color separators in the tab bar using inactive bg except for the last one 2020-03-29 09:20:17 +05:30
Kovid Goyal
86703da917 version 0.17.2 2020-03-29 09:09:16 +05:30
Kovid Goyal
610e9afdf0 Add completion of conf filenames to kitty @ set-colors 2020-03-29 08:41:27 +05:30
Kovid Goyal
e3af9f68d3 Linux: Fix selection of fonts with multiple width variants not preferring the normal width faces
Fixes #2491
2020-03-29 01:52:33 +05:30
Kovid Goyal
747ac85e7c Add an :option:launch --watcher option that allows defining callbacks that are called for various events in the window's life-cycle
Fixes #2440
2020-03-28 12:13:42 +05:30
Kovid Goyal
8c23f9e526 DRYer 2020-03-28 09:20:28 +05:30
Kovid Goyal
e6e339fcd3 ... 2020-03-28 08:44:48 +05:30
Kovid Goyal
f04680ac47 Fix a regression in 0.17 that broke the kitty @ launch remote command and also broke the --tab-title option when creating a new tab.
Fixes #2488
2020-03-28 08:43:32 +05:30
Kovid Goyal
90985cc846 Merge branch 'hints-copy-to-primary-selection' of https://github.com/trygveaa/kitty 2020-03-28 08:21:08 +05:30
Trygve Aaberge
63917944f2 Add an option to hints for copying to the primary selection 2020-03-27 20:23:02 +01:00
Kovid Goyal
793605f80f Update changelog 2020-03-26 22:06:13 +05:30
Kovid Goyal
93a281c7e3 Add a new mappable action `close_other_windows_in_tab` to close all but the active window
Fixes #2484
2020-03-26 22:05:00 +05:30
Kovid Goyal
8f1c6c4d74 Fix #2482 2020-03-26 00:53:19 +05:30
Kovid Goyal
1610dba7ab patch tab bar colors correctly 2020-03-26 00:46:30 +05:30
Kovid Goyal
d9d419991c Respect tab_bar_background again 2020-03-26 00:41:19 +05:30
Kovid Goyal
f9e86b19aa Fix #2480 2020-03-26 00:20:10 +05:30
Kovid Goyal
fffb976e43 Fix blank space at the start of tab bar in powerline style when first tab is inactive
Fix #2478
2020-03-25 19:20:35 +05:30
Kovid Goyal
0da566b49f Hints kitten: Adjust the default regex used to detect line numbers to handle line+column numbers
See #2268
2020-03-25 10:03:25 +05:30
Kovid Goyal
da55717d20 The splits layout needs its own draw_minimal_borders implementation 2020-03-25 09:54:06 +05:30
Kovid Goyal
254836902c Merge branch 'fix/window-border' of https://github.com/pyrho/kitty 2020-03-25 09:35:46 +05:30
Damien Rajon
d01f8d1865 fix(window): inactive window border fix
Fixes #2474.
2020-03-25 00:09:10 +01:00
Kovid Goyal
a46c3f7007 Replace use of cast() 2020-03-24 22:03:10 +05:30
Kovid Goyal
4e58062025 Improve rendering of :option: in cli docs 2020-03-24 22:03:00 +05:30
18 changed files with 208 additions and 39 deletions

View File

@@ -4,6 +4,37 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.17.2 [2020-03-29]
--------------------
- Add a :option:`launch --watcher` option that allows defining callbacks
that are called for various events in the window's life-cycle (:iss:`2440`)
- Fix a regression in 0.17 that broke drawing of borders with non-minimal
borders (:iss:`2474`)
- Hints kitten: Allow copying to primary selection as well as clipboard
(:pull:`2487`)
- Add a new mappable action ``close_other_windows_in_tab`` to close all but the
active window (:iss:`2484`)
- Hints kitten: Adjust the default regex used to detect line numbers to handle
line+column numbers (:iss:`2268`)
- Fix blank space at the start of tab bar in the powerline style when first tab is
inactive (:iss:`2478`)
- Fix regression causing incorrect rendering of separators in tab bar when
defining a tab bar background color (:pull:`2480`)
- Fix a regression in 0.17 that broke the kitty @ launch remote command and
also broke the --tab-title option when creating a new tab. (:iss:`2488`)
- Linux: Fix selection of fonts with multiple width variants not preferring
the normal width faces (:iss:`2491`)
0.17.1 [2020-03-24]
--------------------

View File

@@ -192,6 +192,12 @@ Similarly, you can detach the current tab, with::
# asks which OS Window to move the tab into
map ctrl+f4 detach_tab ask
Finally, you can define a shortcut to close all windows in a tab other than
the currently active window::
map f9 close_other_windows_in_tab
Other keyboard shortcuts
----------------------------------

View File

@@ -61,6 +61,35 @@ currently active kitty window. For example::
map f1 launch my-program @active-kitty-window-id
Watching launched windows
---------------------------
The :option:`launch --watcher` option allows you to specify python functions
that will be called at specific events, such as when the window is resized or
closed. Simply specify the path to a python module that specifies callback
functions for the events you are interested in, for example:
.. code-block:: python
def on_resize(boss, window, data):
# Here data will contain old_geometry and new_geometry
def on_close(boss, window, data):
# called when window is closed, typically when the program running in
# it exits.
Every callback is passed a reference to the global ``Boss`` object as well as
the ``Window`` object the action is occurring on. The ``data`` object is
mapping that contains event dependent data. Some useful methods and attributes
for the ``Window`` object are: ``as_text(as_ans=False, add_history=False,
add_wrap_markers=False, alternate_screen=False)`` with which you can get the
contents of the window and its scrollback buffer. Similarly,
``window.child.pid`` is the PID of the processes that was launched
in the window and ``window.id`` is the internal kitty ``id`` of the
window.
Syntax reference
------------------

View File

@@ -48,6 +48,9 @@ try:
except ImportError:
has_highlighter = False
def highlight_collection(collection: 'Collection', aliases: Optional[Dict[str, str]] = None) -> Union[str, Dict[str, 'DiffHighlight']]:
return ''
INITIALIZING, COLLECTED, DIFFED, COMMAND, MESSAGE = range(5)
ESCAPE = K['ESCAPE']

View File

@@ -21,7 +21,7 @@ from kitty.key_encoding import (
KeyEvent, backspace_key, enter_key, key_defs as K
)
from kitty.typing import BossType, KittyCommonOpts
from kitty.utils import ScreenSize, screen_size_function
from kitty.utils import ScreenSize, screen_size_function, set_primary_selection
from ..tui.handler import Handler, result_handler
from ..tui.loop import Loop
@@ -349,7 +349,7 @@ def parse_input(text: str) -> str:
def linenum_marks(text: str, args: HintsCLIOptions, Mark: Type[Mark], extra_cli_args: Sequence[str], *a: Any) -> Generator[Mark, None, None]:
regex = args.regex
if regex == DEFAULT_REGEX:
regex = r'(?P<path>(?:\S*/\S+)|(?:\S+[.][a-zA-Z0-9]{2,7})):(?P<line>\d+)'
regex = r'(?P<path>(?:\S*/\S+?)|(?:\S+[.][a-zA-Z0-9]{2,7})):(?P<line>\d+)'
yield from mark(regex, [brackets, quotes], text, args)
@@ -360,12 +360,8 @@ def load_custom_processor(customize_processing: str) -> Any:
return {k: getattr(m, k) for k in dir(m)}
if customize_processing == '::linenum::':
return {'mark': linenum_marks, 'handle_result': linenum_handle_result}
from kitty.constants import config_dir
customize_processing = os.path.expandvars(os.path.expanduser(customize_processing))
if os.path.isabs(customize_processing):
custom_path = customize_processing
else:
custom_path = os.path.join(config_dir, customize_processing)
from kitty.constants import resolve_custom_file
custom_path = resolve_custom_file(customize_processing)
import runpy
return runpy.run_path(custom_path, run_name='__main__')
@@ -413,9 +409,11 @@ OPTIONS = r'''
type=list
What program to use to open matched text. Defaults to the default open program
for the operating system. Use a value of :file:`-` to paste the match into the
terminal window instead. A value of :file:`@` will copy the match to the clipboard.
A value of :file:`default` will run the default open program. Can be specified
multiple times to run multiple programs.
terminal window instead. A value of :file:`@` will copy the match to the
clipboard. A value of :file:`*` will copy the match to the primary selection
(on systems that support primary selections). A value of :file:`default` will
run the default open program. Can be specified multiple times to run multiple
programs.
--type
@@ -629,6 +627,8 @@ def handle_result(args: List[str], data: Dict[str, Any], target_window_id: int,
w.paste(joined_text())
elif program == '@':
set_clipboard_string(joined_text())
elif program == '*':
set_primary_selection(joined_text())
else:
cwd = None
w = boss.window_id_map.get(target_window_id)

View File

@@ -96,7 +96,9 @@ def opt(text: str) -> str:
def option(x: str) -> str:
idx = x.find('-')
idx = x.rfind('--')
if idx < 0:
idx = x.find('-')
if idx > -1:
x = x[idx:]
parts = map(bold, x.split())
@@ -119,6 +121,10 @@ def file(x: str) -> str:
return italic(x)
def doc(x: str) -> str:
return f'https://sw.kovidgoyal.net/kitty/{x}.html'
OptionSpecSeq = List[Union[str, OptionDict]]

View File

@@ -6,7 +6,7 @@ import re
from functools import partial
from typing import (
Any, Callable, Dict, Generator, Iterable, List, Match, Optional, Sequence,
Set, Tuple, Union, cast, get_type_hints
Set, Tuple, Union, get_type_hints
)
from .utils import to_bool
@@ -156,7 +156,7 @@ def remove_markup(text: str) -> str:
'layouts': 'https://sw.kovidgoyal.net/kitty/index.html#layouts',
'sessions': 'https://sw.kovidgoyal.net/kitty/index.html#sessions',
}[m.group(2)]
return cast(str, m.group(2))
return str(m.group(2))
return re.sub(r':([a-zA-Z0-9]+):`(.+?)`', sub, text, flags=re.DOTALL)

View File

@@ -20,7 +20,7 @@ class Version(NamedTuple):
appname: str = 'kitty'
version: Version = Version(0, 17, 1)
version: Version = Version(0, 17, 2)
str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat
@@ -198,3 +198,10 @@ def running_in_kitty(set_val: Optional[bool] = None) -> bool:
if set_val is not None:
setattr(running_in_kitty, 'ans', set_val)
return bool(getattr(running_in_kitty, 'ans', False))
def resolve_custom_file(path: str) -> str:
path = os.path.expandvars(os.path.expanduser(path))
if not os.path.isabs(path):
path = os.path.join(config_dir, path)
return path

View File

@@ -323,6 +323,7 @@ FC_MONO: int = 100
FC_DUAL: int
FC_WEIGHT_REGULAR: int
FC_WEIGHT_BOLD: int
FC_WIDTH_NORMAL: int
FC_SLANT_ROMAN: int
FC_SLANT_ITALIC: int
BORDERS_PROGRAM: int
@@ -402,6 +403,7 @@ class FontConfigPattern(TypedDict):
style: str
spacing: str
weight: int
width: int
slant: int
hint_style: int
subpixel: int

View File

@@ -47,6 +47,7 @@ pattern_as_dict(FcPattern *pat) {
S(FC_FULLNAME, full_name);
S(FC_POSTSCRIPT_NAME, postscript_name);
I(FC_WEIGHT, weight);
I(FC_WIDTH, width)
I(FC_SLANT, slant);
I(FC_HINT_STYLE, hint_style);
I(FC_INDEX, index);
@@ -247,5 +248,7 @@ init_fontconfig_library(PyObject *module) {
PyModule_AddIntMacro(module, FC_DUAL);
PyModule_AddIntMacro(module, FC_MONO);
PyModule_AddIntMacro(module, FC_CHARCELL);
PyModule_AddIntMacro(module, FC_WIDTH_NORMAL);
return true;
}

View File

@@ -8,7 +8,7 @@ from typing import Dict, Generator, List, Optional, Tuple, cast
from kitty.fast_data_types import (
FC_DUAL, FC_MONO, FC_SLANT_ITALIC, FC_SLANT_ROMAN, FC_WEIGHT_BOLD,
FC_WEIGHT_REGULAR, fc_list, fc_match as fc_match_impl
FC_WEIGHT_REGULAR, FC_WIDTH_NORMAL, fc_list, fc_match as fc_match_impl
)
from kitty.options_stub import Options
from kitty.typing import FontConfigPattern
@@ -73,11 +73,13 @@ def find_best_match(family: str, bold: bool = False, italic: bool = False, monos
q = family_name_to_key(family)
font_map = all_fonts_map(monospaced)
def score(candidate: FontConfigPattern) -> Tuple[int, int]:
def score(candidate: FontConfigPattern) -> Tuple[int, int, int]:
bold_score = abs((FC_WEIGHT_BOLD if bold else FC_WEIGHT_REGULAR) - candidate.get('weight', 0))
italic_score = abs((FC_SLANT_ITALIC if italic else FC_SLANT_ROMAN) - candidate.get('slant', 0))
monospace_match = 0 if candidate.get('spacing') == 'MONO' else 1
return bold_score + italic_score, monospace_match
width_score = abs(candidate.get('width', FC_WIDTH_NORMAL) - FC_WIDTH_NORMAL)
return bold_score + italic_score, monospace_match, width_score
# First look for an exact match
for selector in ('ps_map', 'full_map', 'family_map'):

View File

@@ -6,14 +6,15 @@
from functools import lru_cache
from typing import Any, Dict, List, Optional, Sequence, Tuple
from .boss import Boss
from .child import Child
from .cli import parse_args
from .cli_stub import LaunchCLIOptions
from .constants import resolve_custom_file
from .fast_data_types import set_clipboard_string
from .utils import set_primary_selection
from .window import Window
from .boss import Boss
from .tabs import Tab
from .utils import set_primary_selection
from .window import Watchers, Window
try:
from typing import TypedDict
@@ -148,6 +149,14 @@ defaults to :code:`kitty`.
--os-window-name
Set the WM_NAME property on X11 for the newly created OS Window when using
:option:`launch --type`=os-window. Defaults to :option:`launch --os-window-class`.
--watcher -w
type=list
Path to a python file. Appropriately named functions in this file will be called
for various events, such as when the window is resized or closed. See the section
on watchers in the launch command documentation :doc:`launch`. Relative paths are
resolved relative to the kitty config directory.
'''
@@ -176,7 +185,7 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Optional[Tab]
tm = boss.active_tab_manager
if tm:
tab: Optional[Tab] = tm.new_tab(empty_tab=True, location=opts.location)
if opts.tab_title and tab:
if opts.tab_title and tab is not None:
tab.set_title(opts.tab_title)
else:
tab = None
@@ -184,7 +193,7 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Optional[Tab]
oswid = boss.add_os_window(wclass=opts.os_window_class, wname=opts.os_window_name)
tm = boss.os_window_map[oswid]
tab = tm.new_tab(empty_tab=True)
if opts.tab_title:
if opts.tab_title and tab is not None:
tab.set_title(opts.tab_title)
else:
tab = target_tab or boss.active_tab
@@ -192,6 +201,23 @@ def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Optional[Tab]
return tab
def load_watch_modules(opts: LaunchCLIOptions) -> Optional[Watchers]:
if not opts.watcher:
return None
import runpy
ans = Watchers()
for path in opts.watcher:
path = resolve_custom_file(path)
m = runpy.run_path(path, run_name='__kitty_watcher__')
w = m.get('on_close')
if callable(w):
ans.on_close.append(w)
w = m.get('on_resize')
if callable(w):
ans.on_resize.append(w)
return ans
class LaunchKwds(TypedDict):
allow_remote_control: bool
@@ -274,7 +300,8 @@ def launch(boss: Boss, opts: LaunchCLIOptions, args: List[str], target_tab: Opti
else:
tab = tab_for_window(boss, opts, target_tab)
if tab is not None:
new_window: Window = tab.new_window(env=env or None, **kw)
watchers = load_watch_modules(opts)
new_window: Window = tab.new_window(env=env or None, watchers=watchers or None, **kw)
if opts.keep_focus and active:
boss.set_active_window(active, switch_os_window_if_needed=True)
return new_window

View File

@@ -549,7 +549,7 @@ class Layout: # {{{
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
for w in windows:
if (w is active_window and draw_active_borders) or w.needs_attention:
if w is not active_window or draw_active_borders or w.needs_attention:
yield all_borders
else:
yield no_borders
@@ -1512,6 +1512,13 @@ class Splits(Layout):
else:
p2.two = w1
def minimal_borders(self, windows: WindowList, active_window: Optional[WindowType], needs_borders_map: Dict[int, bool]) -> Generator[Borders, None, None]:
for w in windows:
if (w is active_window and draw_active_borders) or w.needs_attention:
yield all_borders
else:
yield no_borders
def layout_action(self, action_name: str, args: Sequence[str], all_windows: WindowList, active_window_idx: int) -> Optional[Union[bool, int]]:
if action_name == 'rotate':
args = args or ('90',)

View File

@@ -5,6 +5,7 @@
from typing import TYPE_CHECKING, Optional
from kitty.cli_stub import LaunchCLIOptions
from kitty.launch import (
launch as do_launch, options_spec as launch_options_spec,
parse_launch_args
@@ -16,7 +17,7 @@ from .base import (
)
if TYPE_CHECKING:
from kitty.cli_stub import LaunchRCOptions as CLIOptions, LaunchCLIOptions
from kitty.cli_stub import LaunchRCOptions as CLIOptions
class Launch(RemoteCommand):

View File

@@ -57,6 +57,7 @@ Restore all colors to the values they had at kitty startup. Note that if you spe
this option, any color arguments are ignored and --configured and --all are implied.
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
argspec = 'COLOR_OR_FILE ...'
args_completion = {'files': ('CONF files', ('*.conf',))}
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
final_colors: Dict[str, int] = {}

View File

@@ -81,8 +81,11 @@ def draw_tab_with_separator(draw_data: DrawData, screen: Screen, tab: TabBarData
screen.draw(' ' * trailing_spaces)
end = screen.cursor.x
screen.cursor.bold = screen.cursor.italic = False
screen.cursor.fg = screen.cursor.bg = 0
screen.cursor.fg = 0
if not is_last:
screen.cursor.bg = as_rgb(color_as_int(draw_data.inactive_bg))
screen.draw(draw_data.sep)
screen.cursor.bg = 0
return end
@@ -137,6 +140,7 @@ def draw_tab_with_powerline(draw_data: DrawData, screen: Screen, tab: TabBarData
screen.draw('')
screen.cursor.fg = tab_fg
elif screen.cursor.x == 0:
screen.cursor.bg = tab_bg
screen.draw(' ')
start_draw = 1
@@ -182,7 +186,7 @@ class TabBar:
s.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
s.color_profile.set_configured_colors(
color_as_int(opts.inactive_tab_foreground),
color_as_int(opts.background)
color_as_int(opts.tab_bar_background or opts.background)
)
self.blank_rects: Tuple[Rect, ...] = ()
sep = opts.tab_separator
@@ -226,10 +230,13 @@ class TabBar:
self.draw_data = self.draw_data._replace(default_bg=color_from_int(spec['tab_bar_background']))
elif 'background' in spec and not self.opts.tab_bar_background:
self.draw_data = self.draw_data._replace(default_bg=color_from_int(spec['background']))
self.screen.color_profile.set_configured_colors(
spec.get('inactive_tab_foreground', color_as_int(self.opts.inactive_tab_foreground)),
spec.get('inactive_tab_background', color_as_int(self.opts.inactive_tab_background))
)
fg = spec.get('inactive_tab_foreground', color_as_int(self.opts.inactive_tab_foreground))
bg = spec.get('tab_bar_background', False)
if bg is None:
bg = color_as_int(self.opts.background)
elif bg is False:
bg = color_as_int(self.opts.tab_bar_background or self.opts.background)
self.screen.color_profile.set_configured_colors(fg, bg)
def layout(self) -> None:
central, tab_bar, vw, vh, cell_width, cell_height = viewport_for_window(self.os_window_id)

View File

@@ -26,7 +26,7 @@ from .layout import (
from .options_stub import Options
from .tab_bar import TabBar, TabBarData
from .utils import log_error, resolved_shell
from .window import Window, WindowDict
from .window import Window, WindowDict, Watchers
from .typing import TypedDict, SessionTab, SessionType
@@ -345,11 +345,15 @@ class Tab: # {{{
location: Optional[str] = None,
copy_colors_from: Optional[Window] = None,
allow_remote_control: bool = False,
marker: Optional[str] = None
marker: Optional[str] = None,
watchers: Optional[Watchers] = None
) -> Window:
child = self.launch_child(
use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env, allow_remote_control=allow_remote_control)
window = Window(self, child, self.opts, self.args, override_title=override_title, copy_colors_from=copy_colors_from)
window = Window(
self, child, self.opts, self.args, override_title=override_title,
copy_colors_from=copy_colors_from, watchers=watchers
)
if overlay_for is not None:
overlaid = next(w for w in self.windows if w.id == overlay_for)
window.overlay_for = overlay_for
@@ -384,6 +388,13 @@ class Tab: # {{{
if self.windows:
self.remove_window(self.windows[self.active_window_idx])
def close_other_windows_in_tab(self) -> None:
if len(self.windows) > 1:
active_window = self.windows[self.active_window_idx]
for window in tuple(self.windows):
if window is not active_window:
self.remove_window(window)
def previous_active_window_idx(self, num: int) -> Optional[int]:
try:
old_window_id = self.active_window_history[-num]

View File

@@ -10,8 +10,8 @@ from collections import deque
from enum import IntEnum
from itertools import chain
from typing import (
Any, Callable, Deque, Dict, List, Optional, Pattern, Sequence, Tuple,
Union
Any, Callable, Deque, Dict, Iterable, List, Optional, Pattern, Sequence,
Tuple, Union
)
from .child import ProcessDesc
@@ -32,7 +32,7 @@ from .keys import defines, extended_key_event, keyboard_mode_name
from .options_stub import Options
from .rgb import to_color
from .terminfo import get_capabilities
from .typing import ChildType, TabType, TypedDict
from .typing import BossType, ChildType, TabType, TypedDict
from .utils import (
color_as_int, get_primary_selection, load_shaders, open_cmd, open_url,
parse_color_set, read_shell_environment, sanitize_title,
@@ -77,6 +77,19 @@ DYNAMIC_COLOR_CODES = {
DYNAMIC_COLOR_CODES.update({k+100: v for k, v in DYNAMIC_COLOR_CODES.items()})
class Watcher:
def __call__(self, boss: BossType, window: 'Window', data: Dict[str, Any]) -> None:
pass
class Watchers:
def __init__(self) -> None:
self.on_resize: List[Watcher] = []
self.on_close: List[Watcher] = []
def calculate_gl_geometry(window_geometry: WindowGeometry, viewport_width: int, viewport_height: int, cell_width: int, cell_height: int) -> ScreenGeometry:
dx, dy = 2 * cell_width / viewport_width, 2 * cell_height / viewport_height
xmargin = window_geometry.left / viewport_width
@@ -181,8 +194,10 @@ class Window:
opts: Options,
args: CLIOptions,
override_title: Optional[str] = None,
copy_colors_from: Optional['Window'] = None
copy_colors_from: Optional['Window'] = None,
watchers: Optional[Watchers] = None
):
self.watchers = watchers or Watchers()
self.action_on_close: Optional[Callable] = None
self.action_on_removal: Optional[Callable] = None
self.current_marker_spec: Optional[Tuple[str, Union[str, Tuple[Tuple[int, str], ...]]]] = None
@@ -303,6 +318,7 @@ class Window:
if not self.pty_resized_once:
self.pty_resized_once = True
self.child.mark_terminal_ready()
self.call_watchers(self.watchers.on_resize, {'old_geometry': self.geometry, 'new_geometry': new_geometry})
else:
sg = self.update_position(new_geometry)
self.geometry = g = new_geometry
@@ -536,7 +552,17 @@ class Window:
return ''.join((l.rstrip() or '\n') for l in lines)
return ''.join(lines)
def call_watchers(self, which: Iterable[Watcher], data: Dict[str, Any]) -> None:
boss = get_boss()
for w in which:
try:
w(boss, self, data)
except Exception:
import traceback
traceback.print_exc()
def destroy(self) -> None:
self.call_watchers(self.watchers.on_close, {})
self.destroyed = True
if hasattr(self, 'screen'):
# Remove cycles so that screen is de-allocated immediately