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:
Kovid Goyal 2018-02-10 09:58:15 +05:30
parent feeba9b5f5
commit a14cf81422
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 109 additions and 65 deletions

View File

@ -8,7 +8,7 @@ from gettext import gettext as _
from weakref import WeakValueDictionary
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 .fast_data_types import (
ChildMonitor, create_os_window, current_os_window, destroy_global_data,
@ -62,8 +62,9 @@ class DumpCommands: # {{{
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.cached_values = cached_values
self.os_window_map = {}
self.cursor_blinking = True
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):
dpi_changed = False
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
os_window_id = create_os_window(w, h, appname, wname or self.args.name or cls, cls)
if startup_id:
@ -359,7 +360,7 @@ class Boss:
w.paste('\n'.join(paths))
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)
if tm is not None:
tm.destroy()

View File

@ -10,13 +10,14 @@ import shlex
import sys
import tempfile
from collections import namedtuple
from contextlib import contextmanager
from . import fast_data_types as defines
from .config_utils import (
init_config, parse_config_base, positive_float, positive_int, to_bool,
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 .layout import all_layouts
from .utils import safe_print
@ -92,7 +93,10 @@ def parse_shortcut(sc):
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):
@ -108,7 +112,7 @@ def parse_key_action(action):
elif func == 'send_text':
args = rest.split(' ', 1)
elif func == 'goto_tab':
args = (max(0, int(rest)),)
args = (max(0, int(rest)), )
elif func in shlex_actions:
args = shlex.split(rest)
return KeyAction(func, args)
@ -172,7 +176,8 @@ def parse_symbol_map(val):
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):
@ -231,7 +236,11 @@ def tab_separator(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):
@ -242,8 +251,9 @@ def url_style(x):
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 = {
'allow_remote_control': to_bool,
@ -313,7 +323,9 @@ def special_handling(key, val, ans):
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):
@ -321,13 +333,21 @@ def parse_config(lines, check_keys=True):
'keymap': {},
'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
Options, defaults = init_config(default_config_path, parse_config)
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'})
@ -393,37 +413,12 @@ def build_ansi_color_table(opts: Options = defaults):
return list(map(col, range(16)))
cached_values = {}
cached_path = os.path.join(config_dir, 'cached.json')
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'
)
def atomic_save(data, path):
fd, p = tempfile.mkstemp(dir=os.path.dirname(path), suffix='.tmp')
try:
with os.fdopen(fd, 'wb') as f:
f.write(json.dumps(cached_values).encode('utf-8'))
os.rename(p, cached_path)
except Exception as err:
safe_print(
'Failed to save cached values with error: {}'.format(err),
file=sys.stderr
)
f.write(data)
os.rename(p, path)
finally:
try:
os.remove(p)
@ -431,13 +426,40 @@ def save_cached_values():
pass
except Exception as err:
safe_print(
'Failed to delete temp file for saved cached values with error: {}'.
format(err),
'Failed to delete temp file {} for atomic save with error: {}'.
format(p, err),
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
if 'window-size' in cached_values and opts.remember_window_size:
ws = cached_values['window-size']

View File

@ -36,6 +36,28 @@ del _get_config_dir
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():
return get_boss.boss

View File

@ -11,11 +11,11 @@ from contextlib import contextmanager
from .borders import load_borders_program
from .boss import Boss
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 .fast_data_types import (
create_os_window, glfw_init, glfw_terminate,
install_sigchld_handler, set_default_window_icon, set_options, show_window
create_os_window, glfw_init, glfw_terminate, install_sigchld_handler,
set_default_window_icon, set_options, show_window
)
from .fonts.box_drawing import set_scale
from .utils import (
@ -40,22 +40,21 @@ def init_graphics():
def run_app(opts, args):
set_scale(opts.box_drawing_scale)
set_options(opts, is_wayland, args.debug_gl)
load_cached_values()
w, h = initial_window_size(opts)
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)
show_window(window_id)
if not is_wayland and not is_macos: # no window icons on wayland
with open(logo_data_file, 'rb') as f:
set_default_window_icon(f.read(), 256, 256)
boss = Boss(window_id, opts, args)
boss.start()
end_startup_notification(startup_ctx)
try:
boss.child_monitor.main_loop()
finally:
boss.destroy()
save_cached_values()
with cached_values_for('main') as cached_values:
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)
startup_ctx = init_startup_notification(window_id)
show_window(window_id)
if not is_wayland and not is_macos: # no window icons on wayland
with open(logo_data_file, 'rb') as f:
set_default_window_icon(f.read(), 256, 256)
boss = Boss(window_id, opts, args, cached_values)
boss.start()
end_startup_notification(startup_ctx)
try:
boss.child_monitor.main_loop()
finally:
boss.destroy()
def ensure_osx_locale():