mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-02 11:32:42 +00:00
feat(config): add kitty pre‑shutdown session save and config updates
This commit is contained in:
1 parent
cae4fb8766
commit
7e2ae53560
6 files changed
+84
-45
No files matched your search
@@ -46,6 +46,7 @@ television
|
||||
.config/mimeapps.list
|
||||
.config/systemd
|
||||
.config/systemd/**
|
||||
.local/bin/kitty-day-save
|
||||
.local/bin/niri-launch
|
||||
.config/fish/auto-Niri.fish
|
||||
.local/bin/cp-appid
|
||||
|
||||
@@ -9,6 +9,13 @@ if [ -f "$HOME/.config/systemd/user/nirinit.service" ] && command -v systemctl >
|
||||
systemctl --user daemon-reload || true
|
||||
systemctl --user enable nirinit.service || true
|
||||
fi
|
||||
|
||||
# Pre-shutdown save of kitty's daily session (dot_config/systemd/user, only on
|
||||
# linux desktop/laptop roles; see .chezmoiignore.tmpl).
|
||||
if [ -f "$HOME/.config/systemd/user/kitty-day-save.service" ] && command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --user daemon-reload || true
|
||||
systemctl --user enable --now kitty-day-save.service || true
|
||||
fi
|
||||
{{ else -}}
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
|
||||
@@ -8,31 +8,34 @@ One file, three entry points (kitty runs it under a different __name__ each):
|
||||
startup_session at it whenever no running kitty owns today's session (an
|
||||
flock held for the owner's lifetime). Every launch after kitty was closed
|
||||
reopens the day; a second concurrent instance starts plain instead of
|
||||
duplicating today's tabs.
|
||||
duplicating today's tabs. `kitty --session <past day>` (the kitty-days tv
|
||||
cable) opens that day as a read-only snapshot instead.
|
||||
- watcher (__kitty_watcher__): SAVE_DELAY seconds after a window opens,
|
||||
closes, moves, gains focus or finishes a command (and every SAVE_EVERY
|
||||
seconds, for output from long-running programs), rewrites the session this
|
||||
instance started with: tabs/splits/cwds, each shell window's scrollback, and
|
||||
the program running in it. On restore the shell `cat`s the scrollback, then
|
||||
re-runs the program. Days opened later via the picker are left as read-only
|
||||
snapshots.
|
||||
- kitten (map ... kitten day_session.py): picker over every archived day,
|
||||
newest first; the choice is opened with goto_session.
|
||||
re-runs the program.
|
||||
- kitten `day_session.py flush` (sent over remote control by kitty-day-save
|
||||
before shutdown/reboot): saves right away, then holds further saves for
|
||||
FREEZE seconds so windows dying during shutdown can't shrink the saved day.
|
||||
"""
|
||||
import fcntl
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import date, timedelta
|
||||
from time import monotonic
|
||||
|
||||
from kittens.tui.handler import result_handler
|
||||
|
||||
ROOT = os.path.expanduser('~/.local/share/kitty-sessions')
|
||||
SAVE_DELAY = 1 # seconds; batches bursts of events, and the most change lost when kitty dies
|
||||
SAVE_EVERY = 30 # seconds; catches output that arrives without any window event
|
||||
FREEZE = 60 # seconds without saves after a flush; long enough for any shutdown, short if it's cancelled
|
||||
SB_VAR = 'day_scrollback' # user var naming a window's scrollback dump; kitty saves/restores it via launch --var
|
||||
UNSERIALIZE = 'kitty-unserialize-data=' # kitty.constants.unserialize_launch_flag
|
||||
# Never replay a command that was mid-run when the session was saved if any word
|
||||
@@ -149,12 +152,14 @@ def on_load(boss, data) -> None:
|
||||
args[1] = UNSERIALIZE + json.dumps(data)
|
||||
return shlex.join(args)
|
||||
|
||||
frozen_until = 0.0
|
||||
|
||||
def save(timer_id: int) -> None:
|
||||
nonlocal last, pending
|
||||
pending = False
|
||||
windows = [w for w in boss.all_windows if w.created_in_session_name == name]
|
||||
# Nothing left in the session means kitty is closing: keep the last good save.
|
||||
if not windows:
|
||||
if not windows or monotonic() < frozen_until:
|
||||
return
|
||||
os.makedirs(sb_dir, exist_ok=True)
|
||||
keep = set()
|
||||
@@ -185,7 +190,14 @@ def on_load(boss, data) -> None:
|
||||
pending = True
|
||||
add_timer(save, SAVE_DELAY, False)
|
||||
|
||||
def flush() -> None:
|
||||
nonlocal frozen_until
|
||||
frozen_until = 0.0
|
||||
save(0)
|
||||
frozen_until = monotonic() + FREEZE
|
||||
|
||||
_schedule_save = schedule
|
||||
boss.day_session_flush = flush # the flush kitten runs in its own module copy, so it finds this via boss
|
||||
add_timer(lambda timer_id: schedule(), SAVE_EVERY, True)
|
||||
|
||||
|
||||
@@ -206,23 +218,26 @@ def main(args: list[str]) -> None:
|
||||
|
||||
@result_handler(no_ui=True)
|
||||
def handle_result(args: list[str], answer: str, target_window_id: int, boss) -> None:
|
||||
from kitty.session import goto_session
|
||||
if 'flush' in args and (flush := getattr(boss, 'day_session_flush', None)):
|
||||
flush()
|
||||
|
||||
days = sorted(glob.glob(os.path.join(ROOT, '*', '*.kitty-session')), key=os.path.basename, reverse=True)
|
||||
if not days:
|
||||
boss.show_error('No day sessions', f'Nothing archived under {ROOT} yet.')
|
||||
return
|
||||
|
||||
def label(path: str) -> str:
|
||||
d = date.fromisoformat(os.path.basename(path).partition('.')[0])
|
||||
return f'{d} {d:%a} week of {os.path.basename(os.path.dirname(path))}'
|
||||
|
||||
boss.choose_entry('Open a day', ((p, label(p)) for p in days), lambda p: p and goto_session(boss, (p,)))
|
||||
def session_arg() -> str | None:
|
||||
"""`--session` from kitty's own command line (geninclude runs inside kitty)."""
|
||||
argv = sys.argv[1:]
|
||||
for i, a in enumerate(argv):
|
||||
if a.startswith('--session='):
|
||||
return a.partition('=')[2]
|
||||
if a == '--session' and i + 1 < len(argv):
|
||||
return argv[i + 1]
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = today_path()
|
||||
if own_day(path):
|
||||
other = session_arg()
|
||||
# An explicit --session for another day must not claim today's lock.
|
||||
if (other is None or os.path.abspath(os.path.expanduser(other)) == path) and own_day(path):
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
try:
|
||||
open(path, 'x').close() # empty session = one tab with the default shell
|
||||
|
||||
@@ -35,7 +35,7 @@ action_alias launch_os launch --cwd=current --type=os-window
|
||||
action_alias launch_ov launch --cwd=current --type=overlay
|
||||
action_alias launch_tb launch --cwd=current --type=tab
|
||||
action_alias launch_hs launch --cwd=current --location=hsplit --bias=25
|
||||
action_alias launch_vs launch --cwd=current --location=vsplit --bias=30
|
||||
action_alias launch_vs launch --cwd=current --location=vsplit --bias=33
|
||||
action_alias launch_vs50 launch --cwd=current --location=vsplit --bias=50
|
||||
|
||||
# panes = kitty windows
|
||||
@@ -84,12 +84,10 @@ map alt+o goto_tab 9
|
||||
# reopens today's session unless another running kitty already owns it: tabs,
|
||||
# splits, cwds, each shell's scrollback and the program running in it. Tabs
|
||||
# made with *_with_cwd / --cwd=current join it and are saved ~1s after each
|
||||
# change. ctrl+shift+d reopens any earlier day.
|
||||
# change, and right before shutdown/reboot (kitty-day-save.service). `tv
|
||||
# kitty-days` opens any earlier day in a new kitty.
|
||||
geninclude day_session.py
|
||||
watcher day_session.py
|
||||
map ctrl+shift+d kitten day_session.py
|
||||
# show only the active day's tabs (plus tabs outside any session)
|
||||
tab_bar_filter session:~ or session:^$
|
||||
|
||||
# split nav (vim-aware)
|
||||
map ctrl+h kitten pass_keys.py neighboring_window left ctrl+h
|
||||
@@ -103,9 +101,11 @@ map super+up resize_window taller
|
||||
map super+down resize_window shorter 3
|
||||
|
||||
tab_bar_style powerline
|
||||
tab_powerline_style slanted
|
||||
tab_bar_align center
|
||||
tab_powerline_style angled
|
||||
tab_bar_align left
|
||||
tab_bar_edge top
|
||||
# always shown, even with one tab: it carries the stack-layout pane indicator
|
||||
tab_bar_min_tabs 1
|
||||
|
||||
# Titles come from ~/.config/kitty/tab_bar.py (`{custom}`): the repo the tab's
|
||||
# cwd belongs to, or the file nvim is editing when nvim is the active process.
|
||||
|
||||
+23
-20
@@ -1,6 +1,7 @@
|
||||
"$schema" = 'https://starship.rs/config-schema.json'
|
||||
palette = "cyberdream"
|
||||
|
||||
|
||||
format = """
|
||||
$username\
|
||||
$hostname\
|
||||
@@ -12,6 +13,8 @@ $cmd_duration\
|
||||
$python\
|
||||
$character"""
|
||||
|
||||
add_newline = true
|
||||
|
||||
right_format = """$time"""
|
||||
|
||||
[directory]
|
||||
@@ -59,30 +62,30 @@ style = "bright-black"
|
||||
|
||||
[palettes.cyberdream]
|
||||
# https://github.com/scottmckendry/cyberdream.nvim
|
||||
black = "#1e2124"
|
||||
red = "#ff6e5e"
|
||||
green = "#5eff6c"
|
||||
yellow = "#f1ff5e"
|
||||
blue = "#5ea1ff"
|
||||
purple = "#bd5eff"
|
||||
cyan = "#5ef1ff"
|
||||
white = "#ffffff"
|
||||
black = "#1e2124"
|
||||
red = "#ff6e5e"
|
||||
green = "#5eff6c"
|
||||
yellow = "#f1ff5e"
|
||||
blue = "#5ea1ff"
|
||||
purple = "#bd5eff"
|
||||
cyan = "#5ef1ff"
|
||||
white = "#ffffff"
|
||||
|
||||
bright-black = "#4a4d4f"
|
||||
bright-red = "#ff8b7e"
|
||||
bright-green = "#7eff89"
|
||||
bright-black = "#4a4d4f"
|
||||
bright-red = "#ff8b7e"
|
||||
bright-green = "#7eff89"
|
||||
bright-yellow = "#f3ff7e"
|
||||
bright-blue = "#7eb3ff"
|
||||
bright-blue = "#7eb3ff"
|
||||
bright-purple = "#ff7ef3"
|
||||
bright-cyan = "#7ef3ff"
|
||||
bright-white = "#ffffff"
|
||||
bright-cyan = "#7ef3ff"
|
||||
bright-white = "#ffffff"
|
||||
|
||||
# Dim variants (usable as named colors in styles)
|
||||
dim-black = "#1c1f22"
|
||||
dim-red = "#d05c50"
|
||||
dim-green = "#4fd05b"
|
||||
dim-black = "#1c1f22"
|
||||
dim-red = "#d05c50"
|
||||
dim-green = "#4fd05b"
|
||||
dim-yellow = "#c5d050"
|
||||
dim-blue = "#4f85d1"
|
||||
dim-blue = "#4f85d1"
|
||||
dim-purple = "#d050c6"
|
||||
dim-cyan = "#4fc5d1"
|
||||
dim-white = "#d0d0d1"
|
||||
dim-cyan = "#4fc5d1"
|
||||
dim-white = "#d0d0d1"
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Save kitty daily sessions before shutdown/reboot
|
||||
PartOf=graphical-session.target
|
||||
After=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=%h/.local/bin/kitty-day-save
|
||||
# Re-arm after a flush, in case the shutdown is cancelled.
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
Reference in new issue
Block a user