From ea24c23fde192f45945830a87fdcf808a603bd9c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 25 Mar 2018 11:47:11 +0530 Subject: [PATCH] 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. --- README.asciidoc | 10 +++++++--- kitty/cli.py | 39 ++++++++++++++++++++++++++++++++------- kitty/constants.py | 22 +++++++++++++++++----- kitty/mouse.c | 3 +++ 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index cf524c615..fe0b634d1 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -321,11 +321,15 @@ a pull request! kitty is highly customizable, everything from keyboard shortcuts, to painting 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 -directory (usually `~/.config/kitty/kitty.conf` on Linux and +config file] for an overview of all customization possibilities. + +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 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 diff --git a/kitty/cli.py b/kitty/cli.py index ded55319a..a8b05e23b 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -11,7 +11,6 @@ from .config import load_config from .constants import appname, defconf, is_macos, str_version from .layout import all_layouts -is_macos OPTIONS = ''' --class dest=cls @@ -32,9 +31,21 @@ only use this if you are running a program that does not set titles. --config type=list -default={config_path} 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 @@ -201,10 +212,10 @@ def parse_option_spec(spec=OPTIONS): current_cmd['choices'] = {x.strip() for x in current_cmd['choices'].split(',')} elif state is HELP: if line: - current_cmd['help'] += ' ' + line + current_cmd['help'] += ' ' + line.lstrip() else: if prev_line: - current_cmd['help'] += '\n' + current_cmd['help'] += '\n\n\t' else: state = NORMAL (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(): if not hasattr(options_spec, 'ans'): 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) ) 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) +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): - config = args.config or (defconf, ) + config = resolve_config(args.config) overrides = (a.replace('=', ' ', 1) for a in args.override or ()) opts = load_config(*config, overrides=overrides) return opts diff --git a/kitty/constants.py b/kitty/constants.py index 920531216..d93905a28 100644 --- a/kitty/constants.py +++ b/kitty/constants.py @@ -27,7 +27,22 @@ def _get_config_dir(): if 'KITTY_CONFIG_DIRECTORY' in os.environ: 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) os.makedirs(ans, exist_ok=True) return ans @@ -46,10 +61,7 @@ def _get_cache_dir(): 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 + os.makedirs(candidate, exist_ok=True) return candidate diff --git a/kitty/mouse.c b/kitty/mouse.c index e167d9c56..18ca25a71 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -16,6 +16,7 @@ static MouseShape mouse_cursor_shape = BEAM; typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction; +// Encoding of mouse events {{{ #define SHIFT_INDICATOR (1 << 2) #define ALT_INDICATOR (1 << 3) #define CONTROL_INDICATOR (1 << 4) @@ -91,6 +92,8 @@ encode_mouse_event(Window *w, int button, MouseAction action, int mods) { } +// }}} + static inline bool contains_mouse(Window *w) { WindowGeometry *g = &w->geometry;