Allow specifying a system wide kitty config file

The system config is merged with any user specific config files, with
options in the user specific config files having higher priority.

Also follow the full XDG spec for finding config files, including
XDG_CONFIG_DIRS.
This commit is contained in:
Kovid Goyal 2018-03-25 11:47:11 +05:30
parent be8f2b8106
commit ea24c23fde
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 59 additions and 15 deletions

View File

@ -321,11 +321,15 @@ a pull request!
kitty is highly customizable, everything from keyboard shortcuts, to painting kitty is highly customizable, everything from keyboard shortcuts, to painting
frames-per-second. See the heavily commented link:kitty/kitty.conf[default frames-per-second. See the heavily commented link:kitty/kitty.conf[default
config file]. By default kitty looks for a config file in the OS config config file] for an overview of all customization possibilities.
directory (usually `~/.config/kitty/kitty.conf` on Linux and
By default kitty looks for a config file in the OS config directories (usually
`~/.config/kitty/kitty.conf` and additionally
`~/Library/Preferences/kitty/kitty.conf` on macOS) but you can pass a specific `~/Library/Preferences/kitty/kitty.conf` on macOS) but you can pass a specific
path via the `--config` option or use the `KITTY_CONFIG_DIRECTORY` environment path via the `--config` option or use the `KITTY_CONFIG_DIRECTORY` environment
variable. variable. See the help for the `--config` option in `kitty --help` for full
details.
== Startup Sessions == Startup Sessions

View File

@ -11,7 +11,6 @@ from .config import load_config
from .constants import appname, defconf, is_macos, str_version from .constants import appname, defconf, is_macos, str_version
from .layout import all_layouts from .layout import all_layouts
is_macos
OPTIONS = ''' OPTIONS = '''
--class --class
dest=cls dest=cls
@ -32,9 +31,21 @@ only use this if you are running a program that does not set titles.
--config --config
type=list type=list
default={config_path}
Specify a path to the configuration file(s) to use. Specify a path to the configuration file(s) to use.
Can be specified multiple times to read multiple configuration files in sequence, which are merged. Can be specified multiple times to read multiple configuration files in
sequence, which are merged. Use the special value NONE to not load a config
file.
If this option is not specified, config files are searched for in the order:
"$XDG_CONFIG_HOME/kitty/kitty.conf", "~/.config/kitty/kitty.conf", {macos_confpath}
"$XDG_CONFIG_DIRS/kitty/kitty.conf". The first one that exists is used as the
config file.
If the environment variable "KITTY_CONFIG_DIRECTORY" is specified, that
directory is always used and the above searching does not happen.
If "/etc/xdg/kitty/kitty.conf" exists it is used as a base config file onto
which any user config files are merged.
--override -o --override -o
@ -201,10 +212,10 @@ def parse_option_spec(spec=OPTIONS):
current_cmd['choices'] = {x.strip() for x in current_cmd['choices'].split(',')} current_cmd['choices'] = {x.strip() for x in current_cmd['choices'].split(',')}
elif state is HELP: elif state is HELP:
if line: if line:
current_cmd['help'] += ' ' + line current_cmd['help'] += ' ' + line.lstrip()
else: else:
if prev_line: if prev_line:
current_cmd['help'] += '\n' current_cmd['help'] += '\n\n\t'
else: else:
state = NORMAL state = NORMAL
(seq if current_cmd.get('condition', True) else disabled).append(current_cmd) (seq if current_cmd.get('condition', True) else disabled).append(current_cmd)
@ -453,7 +464,7 @@ def parse_cmdline(oc, disabled, args=None):
def options_spec(): def options_spec():
if not hasattr(options_spec, 'ans'): if not hasattr(options_spec, 'ans'):
options_spec.ans = OPTIONS.format( options_spec.ans = OPTIONS.format(
appname=appname, config_path=defconf, appname=appname, macos_confpath='~/Library/Preferences/kitty/kitty.conf' if is_macos else '',
window_layout_choices=', '.join(all_layouts) window_layout_choices=', '.join(all_layouts)
) )
return options_spec.ans return options_spec.ans
@ -466,8 +477,22 @@ def parse_args(args=None, ospec=options_spec, usage=None, message=None, appname=
return parse_cmdline(oc, disabled, args=args) return parse_cmdline(oc, disabled, args=args)
SYSTEM_CONF = '/etc/xdg/kitty/kitty.conf'
def resolve_config(config_files_on_cmd_line):
if config_files_on_cmd_line:
if 'NONE' not in config_files_on_cmd_line:
yield SYSTEM_CONF
for cf in config_files_on_cmd_line:
yield cf
else:
yield SYSTEM_CONF
yield defconf
def create_opts(args): def create_opts(args):
config = args.config or (defconf, ) config = resolve_config(args.config)
overrides = (a.replace('=', ' ', 1) for a in args.override or ()) overrides = (a.replace('=', ' ', 1) for a in args.override or ())
opts = load_config(*config, overrides=overrides) opts = load_config(*config, overrides=overrides)
return opts return opts

View File

@ -27,7 +27,22 @@ def _get_config_dir():
if 'KITTY_CONFIG_DIRECTORY' in os.environ: if 'KITTY_CONFIG_DIRECTORY' in os.environ:
return os.path.abspath(os.path.expanduser(os.environ['KITTY_CONFIG_DIRECTORY'])) return os.path.abspath(os.path.expanduser(os.environ['KITTY_CONFIG_DIRECTORY']))
candidate = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME') or ('~/Library/Preferences' if is_macos else '~/.config'))) locations = []
if 'XDG_CONFIG_HOME' in os.environ:
locations.append(os.path.abspath(os.path.expanduser(os.environ['XDG_CONFIG_HOME'])))
locations.append(os.path.expanduser('~/.config'))
if is_macos:
locations.append(os.path.expanduser('~/Library/Preferences'))
if 'XDG_CONFIG_DIRS' in os.environ:
for loc in os.environ['XDG_CONFIG_DIRS'].split(os.pathsep):
locations.append(os.path.abspath(os.path.expanduser(os.environ['XDG_CONFIG_HOME'])))
for loc in locations:
if loc:
q = os.path.join(loc, appname)
if os.access(q, os.W_OK) and os.path.exists(os.path.join(q, 'kitty.conf')):
return q
candidate = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME') or '~/.config'))
ans = os.path.join(candidate, appname) ans = os.path.join(candidate, appname)
os.makedirs(ans, exist_ok=True) os.makedirs(ans, exist_ok=True)
return ans return ans
@ -46,10 +61,7 @@ def _get_cache_dir():
else: else:
candidate = os.environ.get('XDG_CACHE_HOME', '~/.cache') candidate = os.environ.get('XDG_CACHE_HOME', '~/.cache')
candidate = os.path.join(os.path.expanduser(candidate), appname) candidate = os.path.join(os.path.expanduser(candidate), appname)
try: os.makedirs(candidate, exist_ok=True)
os.makedirs(candidate)
except FileExistsError:
pass
return candidate return candidate

View File

@ -16,6 +16,7 @@
static MouseShape mouse_cursor_shape = BEAM; static MouseShape mouse_cursor_shape = BEAM;
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction; typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
// Encoding of mouse events {{{
#define SHIFT_INDICATOR (1 << 2) #define SHIFT_INDICATOR (1 << 2)
#define ALT_INDICATOR (1 << 3) #define ALT_INDICATOR (1 << 3)
#define CONTROL_INDICATOR (1 << 4) #define CONTROL_INDICATOR (1 << 4)
@ -91,6 +92,8 @@ encode_mouse_event(Window *w, int button, MouseAction action, int mods) {
} }
// }}}
static inline bool static inline bool
contains_mouse(Window *w) { contains_mouse(Window *w) {
WindowGeometry *g = &w->geometry; WindowGeometry *g = &w->geometry;