mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-25 09:48:09 +02:00
Store cached window sizes in the cache dir rather than the config dir
A side-effect is that on the very next start kitty wont remember window sizes, apologies for the on convenience.
This commit is contained in:
@@ -8,7 +8,7 @@ from gettext import gettext as _
|
|||||||
from weakref import WeakValueDictionary
|
from weakref import WeakValueDictionary
|
||||||
|
|
||||||
from .cli import create_opts, parse_args
|
from .cli import create_opts, parse_args
|
||||||
from .config import MINIMUM_FONT_SIZE, cached_values, initial_window_size
|
from .config import MINIMUM_FONT_SIZE, initial_window_size
|
||||||
from .constants import appname, set_boss, wakeup
|
from .constants import appname, set_boss, wakeup
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
ChildMonitor, create_os_window, current_os_window, destroy_global_data,
|
ChildMonitor, create_os_window, current_os_window, destroy_global_data,
|
||||||
@@ -62,8 +62,9 @@ class DumpCommands: # {{{
|
|||||||
|
|
||||||
class Boss:
|
class Boss:
|
||||||
|
|
||||||
def __init__(self, os_window_id, opts, args):
|
def __init__(self, os_window_id, opts, args, cached_values):
|
||||||
self.window_id_map = WeakValueDictionary()
|
self.window_id_map = WeakValueDictionary()
|
||||||
|
self.cached_values = cached_values
|
||||||
self.os_window_map = {}
|
self.os_window_map = {}
|
||||||
self.cursor_blinking = True
|
self.cursor_blinking = True
|
||||||
self.shutting_down = False
|
self.shutting_down = False
|
||||||
@@ -85,7 +86,7 @@ class Boss:
|
|||||||
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, size=None, startup_id=None):
|
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, size=None, startup_id=None):
|
||||||
dpi_changed = False
|
dpi_changed = False
|
||||||
if os_window_id is None:
|
if os_window_id is None:
|
||||||
w, h = initial_window_size(self.opts) if size is None else size
|
w, h = initial_window_size(self.opts, self.cached_values) if size is None else size
|
||||||
cls = wclass or self.args.cls or appname
|
cls = wclass or self.args.cls or appname
|
||||||
os_window_id = create_os_window(w, h, appname, wname or self.args.name or cls, cls)
|
os_window_id = create_os_window(w, h, appname, wname or self.args.name or cls, cls)
|
||||||
if startup_id:
|
if startup_id:
|
||||||
@@ -359,7 +360,7 @@ class Boss:
|
|||||||
w.paste('\n'.join(paths))
|
w.paste('\n'.join(paths))
|
||||||
|
|
||||||
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
|
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
|
||||||
cached_values['window-size'] = viewport_width, viewport_height
|
self.cached_values['window-size'] = viewport_width, viewport_height
|
||||||
tm = self.os_window_map.pop(os_window_id, None)
|
tm = self.os_window_map.pop(os_window_id, None)
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
tm.destroy()
|
tm.destroy()
|
||||||
|
|||||||
106
kitty/config.py
106
kitty/config.py
@@ -10,13 +10,14 @@ import shlex
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from . import fast_data_types as defines
|
from . import fast_data_types as defines
|
||||||
from .config_utils import (
|
from .config_utils import (
|
||||||
init_config, parse_config_base, positive_float, positive_int, to_bool,
|
init_config, parse_config_base, positive_float, positive_int, to_bool,
|
||||||
to_color, unit_float
|
to_color, unit_float
|
||||||
)
|
)
|
||||||
from .constants import config_dir
|
from .constants import cache_dir
|
||||||
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
||||||
from .layout import all_layouts
|
from .layout import all_layouts
|
||||||
from .utils import safe_print
|
from .utils import safe_print
|
||||||
@@ -92,7 +93,10 @@ def parse_shortcut(sc):
|
|||||||
|
|
||||||
|
|
||||||
KeyAction = namedtuple('KeyAction', 'func args')
|
KeyAction = namedtuple('KeyAction', 'func args')
|
||||||
shlex_actions = {'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window', 'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'}
|
shlex_actions = {
|
||||||
|
'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window',
|
||||||
|
'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse_key_action(action):
|
def parse_key_action(action):
|
||||||
@@ -108,7 +112,7 @@ def parse_key_action(action):
|
|||||||
elif func == 'send_text':
|
elif func == 'send_text':
|
||||||
args = rest.split(' ', 1)
|
args = rest.split(' ', 1)
|
||||||
elif func == 'goto_tab':
|
elif func == 'goto_tab':
|
||||||
args = (max(0, int(rest)),)
|
args = (max(0, int(rest)), )
|
||||||
elif func in shlex_actions:
|
elif func in shlex_actions:
|
||||||
args = shlex.split(rest)
|
args = shlex.split(rest)
|
||||||
return KeyAction(func, args)
|
return KeyAction(func, args)
|
||||||
@@ -172,7 +176,8 @@ def parse_symbol_map(val):
|
|||||||
|
|
||||||
|
|
||||||
def parse_send_text_bytes(text):
|
def parse_send_text_bytes(text):
|
||||||
return ast.literal_eval("'''" + text.replace("'''", "'\\''") + "'''").encode('utf-8')
|
return ast.literal_eval("'''" + text.replace("'''", "'\\''") + "'''"
|
||||||
|
).encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def parse_send_text(val, keymap):
|
def parse_send_text(val, keymap):
|
||||||
@@ -231,7 +236,11 @@ def tab_separator(x):
|
|||||||
|
|
||||||
|
|
||||||
def tab_font_style(x):
|
def tab_font_style(x):
|
||||||
return {'bold-italic': (True, True), 'bold': (True, False), 'italic': (False, True)}.get(x.lower().replace('_', '-'), (False, False))
|
return {
|
||||||
|
'bold-italic': (True, True),
|
||||||
|
'bold': (True, False),
|
||||||
|
'italic': (False, True)
|
||||||
|
}.get(x.lower().replace('_', '-'), (False, False))
|
||||||
|
|
||||||
|
|
||||||
def tab_bar_edge(x):
|
def tab_bar_edge(x):
|
||||||
@@ -242,8 +251,9 @@ def url_style(x):
|
|||||||
return url_style.map.get(x, url_style.map['curly'])
|
return url_style.map.get(x, url_style.map['curly'])
|
||||||
|
|
||||||
|
|
||||||
url_style.map = dict(((v, i) for i, v in enumerate('none single double curly'.split())))
|
url_style.map = dict(
|
||||||
|
((v, i) for i, v in enumerate('none single double curly'.split()))
|
||||||
|
)
|
||||||
|
|
||||||
type_map = {
|
type_map = {
|
||||||
'allow_remote_control': to_bool,
|
'allow_remote_control': to_bool,
|
||||||
@@ -313,7 +323,9 @@ def special_handling(key, val, ans):
|
|||||||
|
|
||||||
|
|
||||||
defaults = None
|
defaults = None
|
||||||
default_config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kitty.conf')
|
default_config_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)), 'kitty.conf'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_config(lines, check_keys=True):
|
def parse_config(lines, check_keys=True):
|
||||||
@@ -321,13 +333,21 @@ def parse_config(lines, check_keys=True):
|
|||||||
'keymap': {},
|
'keymap': {},
|
||||||
'symbol_map': {},
|
'symbol_map': {},
|
||||||
}
|
}
|
||||||
parse_config_base(lines, defaults, type_map, special_handling, ans, check_keys=check_keys)
|
parse_config_base(
|
||||||
|
lines,
|
||||||
|
defaults,
|
||||||
|
type_map,
|
||||||
|
special_handling,
|
||||||
|
ans,
|
||||||
|
check_keys=check_keys
|
||||||
|
)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
Options, defaults = init_config(default_config_path, parse_config)
|
Options, defaults = init_config(default_config_path, parse_config)
|
||||||
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset(
|
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset(
|
||||||
'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.split()
|
'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.
|
||||||
|
split()
|
||||||
)
|
)
|
||||||
no_op_actions = frozenset({'noop', 'no-op', 'no_op'})
|
no_op_actions = frozenset({'noop', 'no-op', 'no_op'})
|
||||||
|
|
||||||
@@ -393,37 +413,12 @@ def build_ansi_color_table(opts: Options = defaults):
|
|||||||
return list(map(col, range(16)))
|
return list(map(col, range(16)))
|
||||||
|
|
||||||
|
|
||||||
cached_values = {}
|
def atomic_save(data, path):
|
||||||
cached_path = os.path.join(config_dir, 'cached.json')
|
fd, p = tempfile.mkstemp(dir=os.path.dirname(path), suffix='.tmp')
|
||||||
|
|
||||||
|
|
||||||
def load_cached_values():
|
|
||||||
cached_values.clear()
|
|
||||||
try:
|
|
||||||
with open(cached_path, 'rb') as f:
|
|
||||||
cached_values.update(json.loads(f.read().decode('utf-8')))
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
except Exception as err:
|
|
||||||
safe_print(
|
|
||||||
'Failed to load cached values with error: {}'.format(err),
|
|
||||||
file=sys.stderr
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def save_cached_values():
|
|
||||||
fd, p = tempfile.mkstemp(
|
|
||||||
dir=os.path.dirname(cached_path), suffix='cached.json.tmp'
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
with os.fdopen(fd, 'wb') as f:
|
with os.fdopen(fd, 'wb') as f:
|
||||||
f.write(json.dumps(cached_values).encode('utf-8'))
|
f.write(data)
|
||||||
os.rename(p, cached_path)
|
os.rename(p, path)
|
||||||
except Exception as err:
|
|
||||||
safe_print(
|
|
||||||
'Failed to save cached values with error: {}'.format(err),
|
|
||||||
file=sys.stderr
|
|
||||||
)
|
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
os.remove(p)
|
os.remove(p)
|
||||||
@@ -431,13 +426,40 @@ def save_cached_values():
|
|||||||
pass
|
pass
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
safe_print(
|
safe_print(
|
||||||
'Failed to delete temp file for saved cached values with error: {}'.
|
'Failed to delete temp file {} for atomic save with error: {}'.
|
||||||
format(err),
|
format(p, err),
|
||||||
file=sys.stderr
|
file=sys.stderr
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def initial_window_size(opts):
|
@contextmanager
|
||||||
|
def cached_values_for(name):
|
||||||
|
cached_path = os.path.join(cache_dir(), name + '.json')
|
||||||
|
cached_values = {}
|
||||||
|
try:
|
||||||
|
with open(cached_path, 'rb') as f:
|
||||||
|
cached_values.update(json.loads(f.read().decode('utf-8')))
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
except Exception as err:
|
||||||
|
safe_print(
|
||||||
|
'Failed to load cached in {} values with error: {}'.format(name, err),
|
||||||
|
file=sys.stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
yield cached_values
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.dumps(cached_values).encode('utf-8')
|
||||||
|
atomic_save(data, cached_path)
|
||||||
|
except Exception as err:
|
||||||
|
safe_print(
|
||||||
|
'Failed to save cached values with error: {}'.format(err),
|
||||||
|
file=sys.stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def initial_window_size(opts, cached_values):
|
||||||
w, h = opts.initial_window_width, opts.initial_window_height
|
w, h = opts.initial_window_width, opts.initial_window_height
|
||||||
if 'window-size' in cached_values and opts.remember_window_size:
|
if 'window-size' in cached_values and opts.remember_window_size:
|
||||||
ws = cached_values['window-size']
|
ws = cached_values['window-size']
|
||||||
|
|||||||
@@ -36,6 +36,28 @@ del _get_config_dir
|
|||||||
defconf = os.path.join(config_dir, 'kitty.conf')
|
defconf = os.path.join(config_dir, 'kitty.conf')
|
||||||
|
|
||||||
|
|
||||||
|
def _get_cache_dir():
|
||||||
|
if 'KITTY_CACHE_DIRECTORY' in os.environ:
|
||||||
|
candidate = os.path.abspath(os.environ['KITTY_CACHE_DIRECTORY'])
|
||||||
|
elif is_macos:
|
||||||
|
candidate = os.path.join(os.path.expanduser('~/Library/Caches'), appname)
|
||||||
|
else:
|
||||||
|
candidate = os.environ.get('XDG_CACHE_HOME', '~/.cache')
|
||||||
|
candidate = os.path.join(os.path.expanduser(candidate), appname)
|
||||||
|
try:
|
||||||
|
os.makedirs(candidate)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
|
||||||
|
def cache_dir():
|
||||||
|
ans = getattr(cache_dir, 'ans', None)
|
||||||
|
if ans is None:
|
||||||
|
ans = cache_dir.ans = _get_cache_dir()
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def get_boss():
|
def get_boss():
|
||||||
return get_boss.boss
|
return get_boss.boss
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ from contextlib import contextmanager
|
|||||||
from .borders import load_borders_program
|
from .borders import load_borders_program
|
||||||
from .boss import Boss
|
from .boss import Boss
|
||||||
from .cli import create_opts, parse_args
|
from .cli import create_opts, parse_args
|
||||||
from .config import initial_window_size, load_cached_values, save_cached_values
|
from .config import cached_values_for, initial_window_size
|
||||||
from .constants import appname, glfw_path, is_macos, is_wayland, logo_data_file
|
from .constants import appname, glfw_path, is_macos, is_wayland, logo_data_file
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
create_os_window, glfw_init, glfw_terminate,
|
create_os_window, glfw_init, glfw_terminate, install_sigchld_handler,
|
||||||
install_sigchld_handler, set_default_window_icon, set_options, show_window
|
set_default_window_icon, set_options, show_window
|
||||||
)
|
)
|
||||||
from .fonts.box_drawing import set_scale
|
from .fonts.box_drawing import set_scale
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@@ -40,22 +40,21 @@ def init_graphics():
|
|||||||
def run_app(opts, args):
|
def run_app(opts, args):
|
||||||
set_scale(opts.box_drawing_scale)
|
set_scale(opts.box_drawing_scale)
|
||||||
set_options(opts, is_wayland, args.debug_gl)
|
set_options(opts, is_wayland, args.debug_gl)
|
||||||
load_cached_values()
|
with cached_values_for('main') as cached_values:
|
||||||
w, h = initial_window_size(opts)
|
w, h = initial_window_size(opts, cached_values)
|
||||||
window_id = create_os_window(w, h, appname, args.name or args.cls or appname, args.cls or appname, load_all_shaders)
|
window_id = create_os_window(w, h, appname, args.name or args.cls or appname, args.cls or appname, load_all_shaders)
|
||||||
startup_ctx = init_startup_notification(window_id)
|
startup_ctx = init_startup_notification(window_id)
|
||||||
show_window(window_id)
|
show_window(window_id)
|
||||||
if not is_wayland and not is_macos: # no window icons on wayland
|
if not is_wayland and not is_macos: # no window icons on wayland
|
||||||
with open(logo_data_file, 'rb') as f:
|
with open(logo_data_file, 'rb') as f:
|
||||||
set_default_window_icon(f.read(), 256, 256)
|
set_default_window_icon(f.read(), 256, 256)
|
||||||
boss = Boss(window_id, opts, args)
|
boss = Boss(window_id, opts, args, cached_values)
|
||||||
boss.start()
|
boss.start()
|
||||||
end_startup_notification(startup_ctx)
|
end_startup_notification(startup_ctx)
|
||||||
try:
|
try:
|
||||||
boss.child_monitor.main_loop()
|
boss.child_monitor.main_loop()
|
||||||
finally:
|
finally:
|
||||||
boss.destroy()
|
boss.destroy()
|
||||||
save_cached_values()
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_osx_locale():
|
def ensure_osx_locale():
|
||||||
|
|||||||
Reference in New Issue
Block a user