2020-04-05 14:36:06 +00:00
|
|
|
|
# TerminatorConfig - layered config classes
|
|
|
|
|
# Copyright (C) 2006-2010 cmsj@tenshu.net
|
2008-03-08 00:04:41 +00:00
|
|
|
|
#
|
2009-05-07 01:35:23 +00:00
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
|
# the Free Software Foundation, version 2 only.
|
2008-03-08 00:04:41 +00:00
|
|
|
|
#
|
2009-05-07 01:35:23 +00:00
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
2008-03-08 00:04:41 +00:00
|
|
|
|
#
|
2009-05-07 01:35:23 +00:00
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2008-03-08 00:04:41 +00:00
|
|
|
|
|
2009-08-18 11:46:41 +00:00
|
|
|
|
"""Terminator by Chris Jones <cmsj@tenshu.net>
|
2008-03-08 00:04:41 +00:00
|
|
|
|
|
2009-12-22 00:24:53 +00:00
|
|
|
|
Classes relating to configuration
|
|
|
|
|
|
2009-12-26 01:19:42 +00:00
|
|
|
|
>>> DEFAULTS['global_config']['focus']
|
|
|
|
|
'click'
|
2009-12-22 00:24:53 +00:00
|
|
|
|
>>> config = Config()
|
|
|
|
|
>>> config['focus'] = 'sloppy'
|
2009-12-23 00:10:57 +00:00
|
|
|
|
>>> config['focus']
|
|
|
|
|
'sloppy'
|
2009-12-26 01:19:42 +00:00
|
|
|
|
>>> DEFAULTS['global_config']['focus']
|
|
|
|
|
'click'
|
2009-12-23 10:09:53 +00:00
|
|
|
|
>>> config2 = Config()
|
|
|
|
|
>>> config2['focus']
|
|
|
|
|
'sloppy'
|
|
|
|
|
>>> config2['focus'] = 'click'
|
|
|
|
|
>>> config2['focus']
|
|
|
|
|
'click'
|
|
|
|
|
>>> config['focus']
|
|
|
|
|
'click'
|
2010-01-08 01:02:49 +00:00
|
|
|
|
>>> config['geometry_hinting'].__class__.__name__
|
2009-12-28 22:16:47 +00:00
|
|
|
|
'bool'
|
2010-01-05 21:44:12 +00:00
|
|
|
|
>>> plugintest = {}
|
|
|
|
|
>>> plugintest['foo'] = 'bar'
|
|
|
|
|
>>> config.plugin_set_config('testplugin', plugintest)
|
|
|
|
|
>>> config.plugin_get_config('testplugin')
|
|
|
|
|
{'foo': 'bar'}
|
|
|
|
|
>>> config.plugin_get('testplugin', 'foo')
|
|
|
|
|
'bar'
|
2015-02-25 23:02:09 +00:00
|
|
|
|
>>> config.plugin_get('testplugin', 'foo', 'new')
|
|
|
|
|
'bar'
|
|
|
|
|
>>> config.plugin_get('testplugin', 'algo')
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
...
|
|
|
|
|
KeyError: 'ConfigBase::get_item: unknown key algo'
|
|
|
|
|
>>> config.plugin_get('testplugin', 'algo', 1)
|
|
|
|
|
1
|
|
|
|
|
>>> config.plugin_get('anothertestplugin', 'algo', 500)
|
|
|
|
|
500
|
2010-01-14 23:29:47 +00:00
|
|
|
|
>>> config.get_profile()
|
|
|
|
|
'default'
|
|
|
|
|
>>> config.set_profile('my_first_new_testing_profile')
|
|
|
|
|
>>> config.get_profile()
|
|
|
|
|
'my_first_new_testing_profile'
|
|
|
|
|
>>> config.del_profile('my_first_new_testing_profile')
|
|
|
|
|
>>> config.get_profile()
|
|
|
|
|
'default'
|
|
|
|
|
>>> config.list_profiles().__class__.__name__
|
|
|
|
|
'list'
|
|
|
|
|
>>> config.options_set({})
|
|
|
|
|
>>> config.options_get()
|
|
|
|
|
{}
|
|
|
|
|
>>>
|
2009-12-22 00:24:53 +00:00
|
|
|
|
|
|
|
|
|
"""
|
2008-03-08 00:04:41 +00:00
|
|
|
|
|
2009-12-25 21:25:31 +00:00
|
|
|
|
import os
|
2020-10-08 21:11:32 +00:00
|
|
|
|
import shutil
|
2009-12-26 01:19:42 +00:00
|
|
|
|
from copy import copy
|
2018-04-24 18:22:10 +00:00
|
|
|
|
from configobj import ConfigObj, flatten_errors
|
|
|
|
|
from validate import Validator
|
|
|
|
|
from .borg import Borg
|
2021-12-10 11:18:37 +00:00
|
|
|
|
from .util import dbg, err, DEBUG, get_system_config_dir, get_config_dir, dict_diff, update_config_to_cell_height
|
2008-08-15 03:11:24 +00:00
|
|
|
|
|
2017-01-12 02:59:40 +00:00
|
|
|
|
from gi.repository import Gio
|
2010-01-21 21:39:05 +00:00
|
|
|
|
|
2009-05-07 01:35:23 +00:00
|
|
|
|
DEFAULTS = {
|
2009-12-26 01:19:42 +00:00
|
|
|
|
'global_config': {
|
2015-11-07 00:25:01 +00:00
|
|
|
|
'dbus' : True,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'focus' : 'click',
|
2023-06-10 03:16:34 +00:00
|
|
|
|
'handle_size' : -1,
|
2015-11-07 00:25:01 +00:00
|
|
|
|
'geometry_hinting' : False,
|
2010-01-08 01:02:49 +00:00
|
|
|
|
'window_state' : 'normal',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'borderless' : False,
|
2016-12-12 11:27:56 +00:00
|
|
|
|
'extra_styling' : True,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'tab_position' : 'top',
|
2015-06-22 18:06:21 +00:00
|
|
|
|
'broadcast_default' : 'group',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'close_button_on_tab' : True,
|
|
|
|
|
'scroll_tabbar' : False,
|
2011-11-19 11:04:29 +00:00
|
|
|
|
'homogeneous_tabbar' : True,
|
2010-05-15 18:07:07 +00:00
|
|
|
|
'hide_from_taskbar' : False,
|
|
|
|
|
'always_on_top' : False,
|
|
|
|
|
'hide_on_lose_focus' : False,
|
|
|
|
|
'sticky' : False,
|
2012-01-14 20:39:00 +00:00
|
|
|
|
'use_custom_url_handler': False,
|
|
|
|
|
'custom_url_handler' : '',
|
2011-10-07 00:20:54 +00:00
|
|
|
|
'inactive_color_offset': 0.8,
|
2023-02-21 10:04:37 +00:00
|
|
|
|
'inactive_bg_color_offset': 1.0,
|
2010-06-18 12:07:02 +00:00
|
|
|
|
'enabled_plugins' : ['LaunchpadBugURLHandler',
|
2010-06-18 12:08:17 +00:00
|
|
|
|
'LaunchpadCodeURLHandler',
|
|
|
|
|
'APTURLHandler'],
|
2015-07-10 19:37:35 +00:00
|
|
|
|
'suppress_multiple_term_dialog': False,
|
|
|
|
|
'always_split_with_profile': False,
|
2015-11-30 21:23:23 +00:00
|
|
|
|
'putty_paste_style' : False,
|
2020-06-19 05:15:13 +00:00
|
|
|
|
'putty_paste_style_source_clipboard': False,
|
2021-09-12 20:13:01 +00:00
|
|
|
|
'disable_mouse_paste' : False,
|
2015-11-30 23:35:06 +00:00
|
|
|
|
'smart_copy' : True,
|
2020-10-19 21:14:40 +00:00
|
|
|
|
'clear_select_on_copy' : False,
|
2021-12-10 10:58:02 +00:00
|
|
|
|
'cell_width' : 1.0,
|
2021-12-25 13:21:19 +00:00
|
|
|
|
'cell_height' : 1.0,
|
2020-10-17 21:51:19 +00:00
|
|
|
|
'case_sensitive' : True,
|
2020-10-20 13:21:12 +00:00
|
|
|
|
'invert_search' : False,
|
2021-03-04 10:17:26 +00:00
|
|
|
|
'link_single_click' : False,
|
2022-12-29 04:20:28 +00:00
|
|
|
|
'title_at_bottom' : False,
|
|
|
|
|
'detachable_tabs' : True,
|
2023-06-04 11:13:37 +00:00
|
|
|
|
|
|
|
|
|
'new_tab_after_current_tab': False,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
},
|
|
|
|
|
'keybindings': {
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'zoom_in' : '<Control>plus',
|
|
|
|
|
'zoom_out' : '<Control>minus',
|
|
|
|
|
'zoom_normal' : '<Control>0',
|
2020-12-03 18:43:05 +00:00
|
|
|
|
'zoom_in_all' : '',
|
|
|
|
|
'zoom_out_all' : '',
|
|
|
|
|
'zoom_normal_all' : '',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'new_tab' : '<Shift><Control>t',
|
2010-01-18 20:39:46 +00:00
|
|
|
|
'cycle_next' : '<Control>Tab',
|
|
|
|
|
'cycle_prev' : '<Shift><Control>Tab',
|
|
|
|
|
'go_next' : '<Shift><Control>n',
|
|
|
|
|
'go_prev' : '<Shift><Control>p',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'go_up' : '<Alt>Up',
|
|
|
|
|
'go_down' : '<Alt>Down',
|
|
|
|
|
'go_left' : '<Alt>Left',
|
|
|
|
|
'go_right' : '<Alt>Right',
|
2012-04-04 15:48:29 +00:00
|
|
|
|
'rotate_cw' : '<Super>r',
|
|
|
|
|
'rotate_ccw' : '<Super><Shift>r',
|
2022-11-05 06:12:38 +00:00
|
|
|
|
'split_auto' : '<Shift><Control>a',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'split_horiz' : '<Shift><Control>o',
|
|
|
|
|
'split_vert' : '<Shift><Control>e',
|
|
|
|
|
'close_term' : '<Shift><Control>w',
|
|
|
|
|
'copy' : '<Shift><Control>c',
|
|
|
|
|
'paste' : '<Shift><Control>v',
|
2021-10-01 02:47:15 +00:00
|
|
|
|
'paste_selection' : '',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'toggle_scrollbar' : '<Shift><Control>s',
|
|
|
|
|
'search' : '<Shift><Control>f',
|
2013-07-14 19:01:58 +00:00
|
|
|
|
'page_up' : '',
|
|
|
|
|
'page_down' : '',
|
|
|
|
|
'page_up_half' : '',
|
|
|
|
|
'page_down_half' : '',
|
|
|
|
|
'line_up' : '',
|
|
|
|
|
'line_down' : '',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'close_window' : '<Shift><Control>q',
|
|
|
|
|
'resize_up' : '<Shift><Control>Up',
|
|
|
|
|
'resize_down' : '<Shift><Control>Down',
|
|
|
|
|
'resize_left' : '<Shift><Control>Left',
|
|
|
|
|
'resize_right' : '<Shift><Control>Right',
|
|
|
|
|
'move_tab_right' : '<Shift><Control>Page_Down',
|
|
|
|
|
'move_tab_left' : '<Shift><Control>Page_Up',
|
|
|
|
|
'toggle_zoom' : '<Shift><Control>x',
|
|
|
|
|
'scaled_zoom' : '<Shift><Control>z',
|
|
|
|
|
'next_tab' : '<Control>Page_Down',
|
|
|
|
|
'prev_tab' : '<Control>Page_Up',
|
|
|
|
|
'switch_to_tab_1' : '',
|
|
|
|
|
'switch_to_tab_2' : '',
|
|
|
|
|
'switch_to_tab_3' : '',
|
|
|
|
|
'switch_to_tab_4' : '',
|
|
|
|
|
'switch_to_tab_5' : '',
|
|
|
|
|
'switch_to_tab_6' : '',
|
|
|
|
|
'switch_to_tab_7' : '',
|
|
|
|
|
'switch_to_tab_8' : '',
|
|
|
|
|
'switch_to_tab_9' : '',
|
|
|
|
|
'switch_to_tab_10' : '',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'full_screen' : 'F11',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'reset' : '<Shift><Control>r',
|
|
|
|
|
'reset_clear' : '<Shift><Control>g',
|
|
|
|
|
'hide_window' : '<Shift><Control><Alt>a',
|
2020-08-25 19:50:40 +00:00
|
|
|
|
'create_group' : '',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'group_all' : '<Super>g',
|
2014-01-24 22:29:07 +00:00
|
|
|
|
'group_all_toggle' : '',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'ungroup_all' : '<Shift><Super>g',
|
2021-08-06 22:38:27 +00:00
|
|
|
|
'group_win' : '',
|
|
|
|
|
'group_win_toggle' : '',
|
|
|
|
|
'ungroup_win' : '<Shift><Super>w',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'group_tab' : '<Super>t',
|
2014-01-24 22:29:07 +00:00
|
|
|
|
'group_tab_toggle' : '',
|
2010-01-10 00:20:24 +00:00
|
|
|
|
'ungroup_tab' : '<Shift><Super>t',
|
|
|
|
|
'new_window' : '<Shift><Control>i',
|
2010-01-29 23:49:16 +00:00
|
|
|
|
'new_terminator' : '<Super>i',
|
2020-04-25 19:39:47 +00:00
|
|
|
|
'broadcast_off' : '',
|
|
|
|
|
'broadcast_group' : '',
|
|
|
|
|
'broadcast_all' : '',
|
2015-07-19 21:44:41 +00:00
|
|
|
|
'insert_number' : '<Super>1',
|
|
|
|
|
'insert_padded' : '<Super>0',
|
2015-12-02 22:40:55 +00:00
|
|
|
|
'edit_window_title': '<Control><Alt>w',
|
|
|
|
|
'edit_tab_title' : '<Control><Alt>a',
|
|
|
|
|
'edit_terminal_title': '<Control><Alt>x',
|
2015-07-19 21:44:41 +00:00
|
|
|
|
'layout_launcher' : '<Alt>l',
|
2014-08-13 07:36:20 +00:00
|
|
|
|
'next_profile' : '',
|
2015-09-01 20:50:09 +00:00
|
|
|
|
'previous_profile' : '',
|
2020-09-22 20:59:26 +00:00
|
|
|
|
'preferences' : '',
|
2022-11-23 14:32:26 +00:00
|
|
|
|
'preferences_keybindings' : '<Control><Shift>k',
|
2015-09-01 20:50:09 +00:00
|
|
|
|
'help' : 'F1'
|
2009-12-22 00:24:53 +00:00
|
|
|
|
},
|
|
|
|
|
'profiles': {
|
|
|
|
|
'default': {
|
|
|
|
|
'allow_bold' : True,
|
|
|
|
|
'audible_bell' : False,
|
2015-09-29 00:24:36 +00:00
|
|
|
|
'visible_bell' : False,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'urgent_bell' : False,
|
2010-02-11 13:05:12 +00:00
|
|
|
|
'icon_bell' : True,
|
2010-04-13 22:17:52 +00:00
|
|
|
|
'background_color' : '#000000',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'background_darkness' : 0.5,
|
|
|
|
|
'background_type' : 'solid',
|
2021-12-08 15:05:38 +00:00
|
|
|
|
'background_image' : '',
|
2022-11-01 09:30:38 +00:00
|
|
|
|
'background_image_mode' : 'stretch_and_fill',
|
2022-11-01 22:27:17 +00:00
|
|
|
|
'background_image_align_horiz': 'center',
|
|
|
|
|
'background_image_align_vert' : 'middle',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'backspace_binding' : 'ascii-del',
|
2010-01-09 17:42:59 +00:00
|
|
|
|
'delete_binding' : 'escape-sequence',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'cursor_blink' : True,
|
|
|
|
|
'cursor_shape' : 'block',
|
2021-08-14 14:45:18 +00:00
|
|
|
|
'cursor_fg_color' : '',
|
|
|
|
|
'cursor_bg_color' : '',
|
2021-08-14 13:14:02 +00:00
|
|
|
|
'cursor_color_default' : True,
|
2015-11-29 20:11:42 +00:00
|
|
|
|
'term' : 'xterm-256color',
|
|
|
|
|
'colorterm' : 'truecolor',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'font' : 'Mono 10',
|
2010-04-13 22:17:52 +00:00
|
|
|
|
'foreground_color' : '#aaaaaa',
|
2010-02-09 00:23:21 +00:00
|
|
|
|
'show_titlebar' : True,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'scrollbar_position' : "right",
|
|
|
|
|
'scroll_on_keystroke' : True,
|
2015-11-30 16:39:38 +00:00
|
|
|
|
'scroll_on_output' : False,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'scrollback_lines' : 500,
|
2010-03-24 13:22:37 +00:00
|
|
|
|
'scrollback_infinite' : False,
|
2020-04-29 20:49:32 +00:00
|
|
|
|
'disable_mousewheel_zoom': False,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'exit_action' : 'close',
|
2010-04-13 22:17:52 +00:00
|
|
|
|
'palette' : '#2e3436:#cc0000:#4e9a06:#c4a000:\
|
|
|
|
|
#3465a4:#75507b:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:\
|
|
|
|
|
#729fcf:#ad7fa8:#34e2e2:#eeeeec',
|
2016-07-04 14:20:26 +00:00
|
|
|
|
'word_chars' : '-,./?%&#:_',
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'mouse_autohide' : True,
|
|
|
|
|
'login_shell' : False,
|
|
|
|
|
'use_custom_command' : False,
|
|
|
|
|
'custom_command' : '',
|
|
|
|
|
'use_system_font' : True,
|
|
|
|
|
'use_theme_colors' : False,
|
2020-04-25 18:22:32 +00:00
|
|
|
|
'bold_is_bright' : False,
|
2021-12-10 11:18:37 +00:00
|
|
|
|
'cell_height' : 1.0,
|
2021-12-10 10:58:02 +00:00
|
|
|
|
'cell_width' : 1.0,
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'force_no_bell' : False,
|
|
|
|
|
'copy_on_selection' : False,
|
|
|
|
|
'split_to_group' : False,
|
|
|
|
|
'autoclean_groups' : True,
|
|
|
|
|
'http_proxy' : '',
|
2021-08-07 21:55:07 +00:00
|
|
|
|
# Titlebar
|
|
|
|
|
'title_hide_sizetext' : False,
|
|
|
|
|
'title_transmit_fg_color' : '#ffffff',
|
|
|
|
|
'title_transmit_bg_color' : '#c80003',
|
|
|
|
|
'title_receive_fg_color' : '#ffffff',
|
|
|
|
|
'title_receive_bg_color' : '#0076c9',
|
|
|
|
|
'title_inactive_fg_color' : '#000000',
|
|
|
|
|
'title_inactive_bg_color' : '#c0bebf',
|
|
|
|
|
'title_use_system_font' : True,
|
|
|
|
|
'title_font' : 'Sans 9'
|
2009-12-22 00:24:53 +00:00
|
|
|
|
},
|
|
|
|
|
},
|
2009-12-26 19:52:58 +00:00
|
|
|
|
'layouts': {
|
2010-02-02 00:39:41 +00:00
|
|
|
|
'default': {
|
|
|
|
|
'window0': {
|
|
|
|
|
'type': 'Window',
|
|
|
|
|
'parent': ''
|
|
|
|
|
},
|
|
|
|
|
'child1': {
|
|
|
|
|
'type': 'Terminal',
|
|
|
|
|
'parent': 'window0'
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-01 12:11:44 +00:00
|
|
|
|
},
|
2009-12-22 00:24:53 +00:00
|
|
|
|
'plugins': {
|
|
|
|
|
},
|
2008-08-15 12:40:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-12-22 00:24:53 +00:00
|
|
|
|
class Config(object):
|
|
|
|
|
"""Class to provide a slightly richer config API above ConfigBase"""
|
|
|
|
|
base = None
|
|
|
|
|
profile = None
|
2015-07-10 19:37:35 +00:00
|
|
|
|
system_mono_font = None
|
|
|
|
|
system_prop_font = None
|
2010-02-09 22:33:47 +00:00
|
|
|
|
system_focus = None
|
2010-03-10 12:51:16 +00:00
|
|
|
|
inhibited = None
|
2009-12-22 00:24:53 +00:00
|
|
|
|
|
|
|
|
|
def __init__(self, profile='default'):
|
|
|
|
|
self.base = ConfigBase()
|
2010-05-15 13:51:20 +00:00
|
|
|
|
self.set_profile(profile)
|
2010-03-10 12:51:16 +00:00
|
|
|
|
self.inhibited = False
|
2017-01-12 02:59:40 +00:00
|
|
|
|
self.connect_gsetting_callbacks()
|
2008-08-15 12:40:10 +00:00
|
|
|
|
|
2015-02-25 23:02:09 +00:00
|
|
|
|
def __getitem__(self, key, default=None):
|
2009-12-22 00:24:53 +00:00
|
|
|
|
"""Look up a configuration item"""
|
2015-02-25 23:02:09 +00:00
|
|
|
|
return(self.base.get_item(key, self.profile, default=default))
|
2009-12-22 00:24:53 +00:00
|
|
|
|
|
2009-12-23 00:10:57 +00:00
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
|
"""Set a particular configuration item"""
|
|
|
|
|
return(self.base.set_item(key, value, self.profile))
|
|
|
|
|
|
2010-01-13 23:02:17 +00:00
|
|
|
|
def get_profile(self):
|
|
|
|
|
"""Get our profile"""
|
|
|
|
|
return(self.profile)
|
|
|
|
|
|
2021-08-30 15:55:42 +00:00
|
|
|
|
def get_profile_by_name(self, profile):
|
|
|
|
|
"""Get the profile with the specified name"""
|
|
|
|
|
return(self.base.profiles[profile])
|
|
|
|
|
|
2010-05-15 13:51:20 +00:00
|
|
|
|
def set_profile(self, profile, force=False):
|
2009-12-23 00:10:57 +00:00
|
|
|
|
"""Set our profile (which usually means change it)"""
|
2010-05-15 13:51:20 +00:00
|
|
|
|
options = self.options_get()
|
|
|
|
|
if not force and options and options.profile and profile == 'default':
|
|
|
|
|
dbg('overriding default profile to %s' % options.profile)
|
|
|
|
|
profile = options.profile
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Changing profile to %s' % profile)
|
2009-12-23 00:10:57 +00:00
|
|
|
|
self.profile = profile
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if profile not in self.base.profiles:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('%s does not exist, creating' % profile)
|
2009-12-26 19:43:01 +00:00
|
|
|
|
self.base.profiles[profile] = copy(DEFAULTS['profiles']['default'])
|
2009-12-23 00:10:57 +00:00
|
|
|
|
|
2021-08-30 15:55:42 +00:00
|
|
|
|
def add_profile(self, profile, toclone):
|
2010-01-09 15:51:56 +00:00
|
|
|
|
"""Add a new profile"""
|
2021-08-30 15:55:42 +00:00
|
|
|
|
return(self.base.add_profile(profile, toclone))
|
2010-01-09 15:51:56 +00:00
|
|
|
|
|
2009-12-26 19:52:58 +00:00
|
|
|
|
def del_profile(self, profile):
|
|
|
|
|
"""Delete a profile"""
|
2010-01-14 23:29:47 +00:00
|
|
|
|
if profile == self.profile:
|
2010-05-15 14:00:09 +00:00
|
|
|
|
# FIXME: We should solve this problem by updating terminals when we
|
|
|
|
|
# remove a profile
|
2010-01-14 23:29:47 +00:00
|
|
|
|
err('Config::del_profile: Deleting in-use profile %s.' % profile)
|
|
|
|
|
self.set_profile('default')
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if profile in self.base.profiles:
|
2009-12-26 19:52:58 +00:00
|
|
|
|
del(self.base.profiles[profile])
|
2010-05-15 14:00:09 +00:00
|
|
|
|
options = self.options_get()
|
|
|
|
|
if options and options.profile == profile:
|
|
|
|
|
options.profile = None
|
|
|
|
|
self.options_set(options)
|
2009-12-26 19:52:58 +00:00
|
|
|
|
|
2010-01-08 01:02:49 +00:00
|
|
|
|
def rename_profile(self, profile, newname):
|
|
|
|
|
"""Rename a profile"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if profile in self.base.profiles:
|
2010-01-08 01:02:49 +00:00
|
|
|
|
self.base.profiles[newname] = self.base.profiles[profile]
|
|
|
|
|
del(self.base.profiles[profile])
|
2010-01-10 00:53:27 +00:00
|
|
|
|
if profile == self.profile:
|
|
|
|
|
self.profile = newname
|
2010-01-08 01:02:49 +00:00
|
|
|
|
|
2009-12-26 19:52:58 +00:00
|
|
|
|
def list_profiles(self):
|
|
|
|
|
"""List all configured profiles"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
return(list(self.base.profiles.keys()))
|
2009-12-26 19:52:58 +00:00
|
|
|
|
|
2010-02-01 12:11:44 +00:00
|
|
|
|
def add_layout(self, name, layout):
|
2010-01-30 00:27:57 +00:00
|
|
|
|
"""Add a new layout"""
|
2010-02-01 12:11:44 +00:00
|
|
|
|
return(self.base.add_layout(name, layout))
|
2015-07-15 00:51:18 +00:00
|
|
|
|
|
2014-05-19 19:47:11 +00:00
|
|
|
|
def replace_layout(self, name, layout):
|
|
|
|
|
"""Replace an existing layout"""
|
|
|
|
|
return(self.base.replace_layout(name, layout))
|
2010-01-30 00:27:57 +00:00
|
|
|
|
|
|
|
|
|
def del_layout(self, layout):
|
|
|
|
|
"""Delete a layout"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if layout in self.base.layouts:
|
2010-01-30 00:27:57 +00:00
|
|
|
|
del(self.base.layouts[layout])
|
|
|
|
|
|
|
|
|
|
def rename_layout(self, layout, newname):
|
|
|
|
|
"""Rename a layout"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if layout in self.base.layouts:
|
2010-01-30 00:27:57 +00:00
|
|
|
|
self.base.layouts[newname] = self.base.layouts[layout]
|
|
|
|
|
del(self.base.layouts[layout])
|
|
|
|
|
|
|
|
|
|
def list_layouts(self):
|
|
|
|
|
"""List all configured layouts"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
return(list(self.base.layouts.keys()))
|
2010-01-30 00:27:57 +00:00
|
|
|
|
|
2017-01-12 02:59:40 +00:00
|
|
|
|
def connect_gsetting_callbacks(self):
|
|
|
|
|
"""Get system settings and create callbacks for changes"""
|
|
|
|
|
dbg("GSetting connects for system changes")
|
|
|
|
|
# Have to preserve these to self, or callbacks don't happen
|
|
|
|
|
self.gsettings_interface=Gio.Settings.new('org.gnome.desktop.interface')
|
|
|
|
|
self.gsettings_interface.connect("changed::font-name", self.on_gsettings_change_event)
|
|
|
|
|
self.gsettings_interface.connect("changed::monospace-font-name", self.on_gsettings_change_event)
|
|
|
|
|
self.gsettings_wm=Gio.Settings.new('org.gnome.desktop.wm.preferences')
|
|
|
|
|
self.gsettings_wm.connect("changed::focus-mode", self.on_gsettings_change_event)
|
|
|
|
|
|
2015-07-10 19:37:35 +00:00
|
|
|
|
def get_system_prop_font(self):
|
2010-01-21 21:39:05 +00:00
|
|
|
|
"""Look up the system font"""
|
2015-07-10 19:37:35 +00:00
|
|
|
|
if self.system_prop_font is not None:
|
|
|
|
|
return(self.system_prop_font)
|
2017-01-12 02:59:40 +00:00
|
|
|
|
elif 'org.gnome.desktop.interface' not in Gio.Settings.list_schemas():
|
2010-01-21 21:39:05 +00:00
|
|
|
|
return
|
2010-02-09 22:33:47 +00:00
|
|
|
|
else:
|
2017-01-12 02:59:40 +00:00
|
|
|
|
gsettings=Gio.Settings.new('org.gnome.desktop.interface')
|
|
|
|
|
value = gsettings.get_value('font-name')
|
2015-08-01 22:50:24 +00:00
|
|
|
|
if value:
|
|
|
|
|
self.system_prop_font = value.get_string()
|
|
|
|
|
else:
|
|
|
|
|
self.system_prop_font = "Sans 10"
|
2015-07-10 19:37:35 +00:00
|
|
|
|
return(self.system_prop_font)
|
|
|
|
|
|
|
|
|
|
def get_system_mono_font(self):
|
|
|
|
|
"""Look up the system font"""
|
|
|
|
|
if self.system_mono_font is not None:
|
|
|
|
|
return(self.system_mono_font)
|
2017-01-12 02:59:40 +00:00
|
|
|
|
elif 'org.gnome.desktop.interface' not in Gio.Settings.list_schemas():
|
2015-07-10 19:37:35 +00:00
|
|
|
|
return
|
|
|
|
|
else:
|
2017-01-12 02:59:40 +00:00
|
|
|
|
gsettings=Gio.Settings.new('org.gnome.desktop.interface')
|
|
|
|
|
value = gsettings.get_value('monospace-font-name')
|
2015-08-01 22:50:24 +00:00
|
|
|
|
if value:
|
|
|
|
|
self.system_mono_font = value.get_string()
|
|
|
|
|
else:
|
|
|
|
|
self.system_mono_font = "Mono 10"
|
2015-07-10 19:37:35 +00:00
|
|
|
|
return(self.system_mono_font)
|
2010-01-21 21:39:05 +00:00
|
|
|
|
|
|
|
|
|
def get_system_focus(self):
|
|
|
|
|
"""Look up the system focus setting"""
|
2010-02-09 22:33:47 +00:00
|
|
|
|
if self.system_focus is not None:
|
|
|
|
|
return(self.system_focus)
|
2017-01-12 02:59:40 +00:00
|
|
|
|
elif 'org.gnome.desktop.interface' not in Gio.Settings.list_schemas():
|
2010-01-21 21:39:05 +00:00
|
|
|
|
return
|
2010-02-09 22:33:47 +00:00
|
|
|
|
else:
|
2017-01-12 02:59:40 +00:00
|
|
|
|
gsettings=Gio.Settings.new('org.gnome.desktop.wm.preferences')
|
|
|
|
|
value = gsettings.get_value('focus-mode')
|
2012-10-18 21:37:46 +00:00
|
|
|
|
if value:
|
|
|
|
|
self.system_focus = value.get_string()
|
2010-02-09 22:33:47 +00:00
|
|
|
|
return(self.system_focus)
|
2010-01-21 21:39:05 +00:00
|
|
|
|
|
2017-01-12 02:59:40 +00:00
|
|
|
|
def on_gsettings_change_event(self, settings, key):
|
|
|
|
|
"""Handle a gsetting change event"""
|
|
|
|
|
dbg('GSetting change event received. Invalidating caches')
|
2010-02-09 22:33:47 +00:00
|
|
|
|
self.system_focus = None
|
|
|
|
|
self.system_font = None
|
2017-01-12 02:59:40 +00:00
|
|
|
|
self.system_mono_font = None
|
|
|
|
|
# Need to trigger a reconfigure to change active terminals immediately
|
|
|
|
|
if "Terminator" not in globals():
|
2018-04-24 18:22:10 +00:00
|
|
|
|
from .terminator import Terminator
|
2017-01-12 02:59:40 +00:00
|
|
|
|
Terminator().reconfigure()
|
2010-01-21 21:39:05 +00:00
|
|
|
|
|
2009-12-25 21:22:04 +00:00
|
|
|
|
def save(self):
|
|
|
|
|
"""Cause ConfigBase to save our config to file"""
|
2010-03-10 12:51:16 +00:00
|
|
|
|
if self.inhibited is True:
|
|
|
|
|
return(True)
|
|
|
|
|
else:
|
|
|
|
|
return(self.base.save())
|
|
|
|
|
|
|
|
|
|
def inhibit_save(self):
|
|
|
|
|
"""Prevent calls to save() being honoured"""
|
|
|
|
|
self.inhibited = True
|
|
|
|
|
|
|
|
|
|
def uninhibit_save(self):
|
|
|
|
|
"""Allow calls to save() to be honoured"""
|
|
|
|
|
self.inhibited = False
|
2009-12-25 21:22:04 +00:00
|
|
|
|
|
2010-01-11 20:56:30 +00:00
|
|
|
|
def options_set(self, options):
|
|
|
|
|
"""Set the command line options"""
|
|
|
|
|
self.base.command_line_options = options
|
|
|
|
|
|
|
|
|
|
def options_get(self):
|
|
|
|
|
"""Get the command line options"""
|
|
|
|
|
return(self.base.command_line_options)
|
|
|
|
|
|
2015-02-25 23:02:09 +00:00
|
|
|
|
def plugin_get(self, pluginname, key, default=None):
|
|
|
|
|
"""Get a plugin config value, if doesn't exist
|
|
|
|
|
return default if specified
|
|
|
|
|
"""
|
|
|
|
|
return(self.base.get_item(key, plugin=pluginname, default=default))
|
2010-01-05 21:44:12 +00:00
|
|
|
|
|
|
|
|
|
def plugin_set(self, pluginname, key, value):
|
|
|
|
|
"""Set a plugin config value"""
|
|
|
|
|
return(self.base.set_item(key, value, plugin=pluginname))
|
|
|
|
|
|
|
|
|
|
def plugin_get_config(self, plugin):
|
|
|
|
|
"""Return a whole config tree for a given plugin"""
|
|
|
|
|
return(self.base.get_plugin(plugin))
|
|
|
|
|
|
|
|
|
|
def plugin_set_config(self, plugin, tree):
|
|
|
|
|
"""Set a whole config tree for a given plugin"""
|
|
|
|
|
return(self.base.set_plugin(plugin, tree))
|
|
|
|
|
|
2011-12-28 22:00:52 +00:00
|
|
|
|
def plugin_del_config(self, plugin):
|
|
|
|
|
"""Delete a whole config tree for a given plugin"""
|
|
|
|
|
return(self.base.del_plugin(plugin))
|
|
|
|
|
|
2010-02-01 12:11:44 +00:00
|
|
|
|
def layout_get_config(self, layout):
|
|
|
|
|
"""Return a layout"""
|
|
|
|
|
return(self.base.get_layout(layout))
|
|
|
|
|
|
|
|
|
|
def layout_set_config(self, layout, tree):
|
|
|
|
|
"""Set a layout"""
|
|
|
|
|
return(self.base.set_layout(layout, tree))
|
|
|
|
|
|
2009-12-23 00:10:57 +00:00
|
|
|
|
class ConfigBase(Borg):
|
2009-12-22 00:24:53 +00:00
|
|
|
|
"""Class to provide access to our user configuration"""
|
2009-12-26 19:43:01 +00:00
|
|
|
|
loaded = None
|
2010-04-05 22:06:30 +00:00
|
|
|
|
whined = None
|
2009-12-26 19:43:01 +00:00
|
|
|
|
sections = None
|
2009-12-22 00:24:53 +00:00
|
|
|
|
global_config = None
|
|
|
|
|
profiles = None
|
|
|
|
|
keybindings = None
|
|
|
|
|
plugins = None
|
2009-12-26 19:43:01 +00:00
|
|
|
|
layouts = None
|
2010-01-11 20:56:30 +00:00
|
|
|
|
command_line_options = None
|
2021-12-10 11:18:37 +00:00
|
|
|
|
config_file_updated_to_cell_height = False
|
2009-11-20 22:46:50 +00:00
|
|
|
|
|
2009-08-18 11:46:41 +00:00
|
|
|
|
def __init__(self):
|
|
|
|
|
"""Class initialiser"""
|
2008-04-07 20:49:10 +00:00
|
|
|
|
|
2009-12-22 00:24:53 +00:00
|
|
|
|
Borg.__init__(self, self.__class__.__name__)
|
2008-03-08 00:04:41 +00:00
|
|
|
|
|
2009-11-20 22:52:26 +00:00
|
|
|
|
self.prepare_attributes()
|
2018-04-24 18:22:10 +00:00
|
|
|
|
from . import optionparse
|
2012-03-30 19:35:19 +00:00
|
|
|
|
self.command_line_options = optionparse.options
|
2009-12-26 13:39:14 +00:00
|
|
|
|
self.load()
|
2009-11-20 22:52:26 +00:00
|
|
|
|
|
2009-11-20 22:46:50 +00:00
|
|
|
|
def prepare_attributes(self):
|
|
|
|
|
"""Set up our borg environment"""
|
2009-12-26 19:43:01 +00:00
|
|
|
|
if self.loaded is None:
|
|
|
|
|
self.loaded = False
|
2010-04-05 22:06:30 +00:00
|
|
|
|
if self.whined is None:
|
|
|
|
|
self.whined = False
|
2009-12-26 19:43:01 +00:00
|
|
|
|
if self.sections is None:
|
|
|
|
|
self.sections = ['global_config', 'keybindings', 'profiles',
|
|
|
|
|
'layouts', 'plugins']
|
2009-12-22 00:24:53 +00:00
|
|
|
|
if self.global_config is None:
|
2009-12-26 01:19:42 +00:00
|
|
|
|
self.global_config = copy(DEFAULTS['global_config'])
|
2009-12-22 00:24:53 +00:00
|
|
|
|
if self.profiles is None:
|
|
|
|
|
self.profiles = {}
|
2009-12-26 01:19:42 +00:00
|
|
|
|
self.profiles['default'] = copy(DEFAULTS['profiles']['default'])
|
2009-12-22 00:24:53 +00:00
|
|
|
|
if self.keybindings is None:
|
2009-12-26 01:19:42 +00:00
|
|
|
|
self.keybindings = copy(DEFAULTS['keybindings'])
|
2009-12-22 00:24:53 +00:00
|
|
|
|
if self.plugins is None:
|
|
|
|
|
self.plugins = {}
|
2009-12-26 19:43:01 +00:00
|
|
|
|
if self.layouts is None:
|
2010-02-01 12:11:44 +00:00
|
|
|
|
self.layouts = {}
|
|
|
|
|
for layout in DEFAULTS['layouts']:
|
2010-02-02 00:39:41 +00:00
|
|
|
|
self.layouts[layout] = copy(DEFAULTS['layouts'][layout])
|
2009-11-20 22:46:50 +00:00
|
|
|
|
|
2009-12-28 22:06:23 +00:00
|
|
|
|
def defaults_to_configspec(self):
|
|
|
|
|
"""Convert our tree of default values into a ConfigObj validation
|
|
|
|
|
specification"""
|
|
|
|
|
configspecdata = {}
|
|
|
|
|
|
2010-01-22 18:54:36 +00:00
|
|
|
|
keymap = {
|
|
|
|
|
'int': 'integer',
|
|
|
|
|
'str': 'string',
|
|
|
|
|
'bool': 'boolean',
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-28 22:06:23 +00:00
|
|
|
|
section = {}
|
|
|
|
|
for key in DEFAULTS['global_config']:
|
|
|
|
|
keytype = DEFAULTS['global_config'][key].__class__.__name__
|
|
|
|
|
value = DEFAULTS['global_config'][key]
|
2010-01-22 18:54:36 +00:00
|
|
|
|
if keytype in keymap:
|
|
|
|
|
keytype = keymap[keytype]
|
2009-12-28 22:06:23 +00:00
|
|
|
|
elif keytype == 'list':
|
|
|
|
|
value = 'list(%s)' % ','.join(value)
|
|
|
|
|
|
|
|
|
|
keytype = '%s(default=%s)' % (keytype, value)
|
|
|
|
|
|
2012-10-17 22:33:15 +00:00
|
|
|
|
if key == 'custom_url_handler':
|
|
|
|
|
keytype = 'string(default="")'
|
|
|
|
|
|
2009-12-28 22:06:23 +00:00
|
|
|
|
section[key] = keytype
|
|
|
|
|
configspecdata['global_config'] = section
|
|
|
|
|
|
|
|
|
|
section = {}
|
|
|
|
|
for key in DEFAULTS['keybindings']:
|
|
|
|
|
value = DEFAULTS['keybindings'][key]
|
2010-01-10 17:36:55 +00:00
|
|
|
|
if value is None or value == '':
|
2009-12-28 22:06:23 +00:00
|
|
|
|
continue
|
|
|
|
|
section[key] = 'string(default=%s)' % value
|
|
|
|
|
configspecdata['keybindings'] = section
|
|
|
|
|
|
|
|
|
|
section = {}
|
|
|
|
|
for key in DEFAULTS['profiles']['default']:
|
|
|
|
|
keytype = DEFAULTS['profiles']['default'][key].__class__.__name__
|
|
|
|
|
value = DEFAULTS['profiles']['default'][key]
|
2010-01-22 18:54:36 +00:00
|
|
|
|
if keytype in keymap:
|
|
|
|
|
keytype = keymap[keytype]
|
2009-12-28 22:06:23 +00:00
|
|
|
|
elif keytype == 'list':
|
|
|
|
|
value = 'list(%s)' % ','.join(value)
|
2010-01-22 18:54:36 +00:00
|
|
|
|
if keytype == 'string':
|
|
|
|
|
value = '"%s"' % value
|
2009-12-28 22:06:23 +00:00
|
|
|
|
|
|
|
|
|
keytype = '%s(default=%s)' % (keytype, value)
|
|
|
|
|
|
|
|
|
|
section[key] = keytype
|
|
|
|
|
configspecdata['profiles'] = {}
|
|
|
|
|
configspecdata['profiles']['__many__'] = section
|
|
|
|
|
|
2010-02-02 00:39:41 +00:00
|
|
|
|
section = {}
|
|
|
|
|
section['type'] = 'string'
|
|
|
|
|
section['parent'] = 'string'
|
|
|
|
|
section['profile'] = 'string(default=default)'
|
|
|
|
|
section['command'] = 'string(default="")'
|
2010-02-27 13:55:38 +00:00
|
|
|
|
section['position'] = 'string(default="")'
|
2010-02-27 14:18:08 +00:00
|
|
|
|
section['size'] = 'list(default=list(-1,-1))'
|
2010-02-02 00:39:41 +00:00
|
|
|
|
configspecdata['layouts'] = {}
|
|
|
|
|
configspecdata['layouts']['__many__'] = {}
|
|
|
|
|
configspecdata['layouts']['__many__']['__many__'] = section
|
|
|
|
|
|
2010-02-06 15:02:16 +00:00
|
|
|
|
configspecdata['plugins'] = {}
|
|
|
|
|
|
2009-12-28 22:06:23 +00:00
|
|
|
|
configspec = ConfigObj(configspecdata)
|
|
|
|
|
if DEBUG == True:
|
2018-04-24 18:22:10 +00:00
|
|
|
|
configspec.write(open('/tmp/terminator_configspec_debug.txt', 'wb'))
|
2009-12-28 22:06:23 +00:00
|
|
|
|
return(configspec)
|
|
|
|
|
|
2009-12-26 13:39:14 +00:00
|
|
|
|
def load(self):
|
2009-12-22 00:24:53 +00:00
|
|
|
|
"""Load configuration data from our various sources"""
|
2009-12-26 19:43:01 +00:00
|
|
|
|
if self.loaded is True:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('config already loaded')
|
2009-12-26 19:43:01 +00:00
|
|
|
|
return
|
|
|
|
|
|
2020-12-01 20:49:11 +00:00
|
|
|
|
if self.command_line_options and self.command_line_options.config:
|
2013-01-30 13:50:27 +00:00
|
|
|
|
filename = self.command_line_options.config
|
|
|
|
|
else:
|
|
|
|
|
filename = os.path.join(get_config_dir(), 'config')
|
2020-12-01 19:38:29 +00:00
|
|
|
|
if not os.path.exists(filename):
|
|
|
|
|
filename = os.path.join(get_system_config_dir(), 'config')
|
2010-10-15 11:40:29 +00:00
|
|
|
|
dbg('looking for config file: %s' % filename)
|
2009-12-26 19:43:01 +00:00
|
|
|
|
try:
|
2021-12-10 11:18:37 +00:00
|
|
|
|
#
|
|
|
|
|
# Make sure we attempt to update the ‘cell_height’ config
|
|
|
|
|
# only once when starting a new instance of Terminator.
|
|
|
|
|
#
|
|
|
|
|
if not self.config_file_updated_to_cell_height:
|
|
|
|
|
update_config_to_cell_height(filename)
|
|
|
|
|
self.config_file_updated_to_cell_height = True
|
|
|
|
|
|
2009-12-26 19:43:01 +00:00
|
|
|
|
configfile = open(filename, 'r')
|
2018-04-24 18:22:10 +00:00
|
|
|
|
except Exception as ex:
|
2010-04-05 22:06:30 +00:00
|
|
|
|
if not self.whined:
|
|
|
|
|
err('ConfigBase::load: Unable to open %s (%s)' % (filename, ex))
|
|
|
|
|
self.whined = True
|
2009-12-26 19:43:01 +00:00
|
|
|
|
return
|
2010-04-05 22:06:30 +00:00
|
|
|
|
# If we have successfully loaded a config, allow future whining
|
|
|
|
|
self.whined = False
|
2009-12-26 19:43:01 +00:00
|
|
|
|
|
2010-02-08 21:11:38 +00:00
|
|
|
|
try:
|
|
|
|
|
configspec = self.defaults_to_configspec()
|
|
|
|
|
parser = ConfigObj(configfile, configspec=configspec)
|
|
|
|
|
validator = Validator()
|
|
|
|
|
result = parser.validate(validator, preserve_errors=True)
|
2018-04-24 18:22:10 +00:00
|
|
|
|
except Exception as ex:
|
2010-02-08 21:11:38 +00:00
|
|
|
|
err('Unable to load configuration: %s' % ex)
|
|
|
|
|
return
|
2009-12-28 22:06:23 +00:00
|
|
|
|
|
|
|
|
|
if result != True:
|
|
|
|
|
err('ConfigBase::load: config format is not valid')
|
2010-01-22 18:54:36 +00:00
|
|
|
|
for (section_list, key, _other) in flatten_errors(parser, result):
|
2010-01-10 17:36:55 +00:00
|
|
|
|
if key is not None:
|
2010-02-02 00:39:41 +00:00
|
|
|
|
err('[%s]: %s is invalid' % (','.join(section_list), key))
|
2010-01-10 17:36:55 +00:00
|
|
|
|
else:
|
2010-02-02 00:39:41 +00:00
|
|
|
|
err('[%s] missing' % ','.join(section_list))
|
|
|
|
|
else:
|
|
|
|
|
dbg('config validated successfully')
|
2009-12-28 22:06:23 +00:00
|
|
|
|
|
2009-12-26 19:43:01 +00:00
|
|
|
|
for section_name in self.sections:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing section: %s' % section_name)
|
2009-12-26 13:39:14 +00:00
|
|
|
|
section = getattr(self, section_name)
|
2009-12-26 19:43:01 +00:00
|
|
|
|
if section_name == 'profiles':
|
|
|
|
|
for profile in parser[section_name]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing profile: %s' % profile)
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if section_name not in section:
|
2010-02-02 00:39:41 +00:00
|
|
|
|
# FIXME: Should this be outside the loop?
|
2009-12-26 19:43:01 +00:00
|
|
|
|
section[profile] = copy(DEFAULTS['profiles']['default'])
|
|
|
|
|
section[profile].update(parser[section_name][profile])
|
2010-02-01 12:11:44 +00:00
|
|
|
|
elif section_name == 'plugins':
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if section_name not in parser:
|
2010-02-07 12:41:08 +00:00
|
|
|
|
continue
|
2009-12-26 19:43:01 +00:00
|
|
|
|
for part in parser[section_name]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing %s: %s' % (section_name, part))
|
2009-12-26 19:43:01 +00:00
|
|
|
|
section[part] = parser[section_name][part]
|
2010-02-01 12:11:44 +00:00
|
|
|
|
elif section_name == 'layouts':
|
2010-02-02 00:39:41 +00:00
|
|
|
|
for layout in parser[section_name]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing %s: %s' % (section_name, layout))
|
2010-03-05 12:29:02 +00:00
|
|
|
|
if layout == 'default' and \
|
|
|
|
|
parser[section_name][layout] == {}:
|
|
|
|
|
continue
|
2010-02-02 00:39:41 +00:00
|
|
|
|
section[layout] = parser[section_name][layout]
|
2017-02-01 09:03:29 +00:00
|
|
|
|
elif section_name == 'keybindings':
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if section_name not in parser:
|
2017-02-01 09:03:29 +00:00
|
|
|
|
continue
|
|
|
|
|
for part in parser[section_name]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing %s: %s' % (section_name, part))
|
2017-02-01 09:03:29 +00:00
|
|
|
|
if parser[section_name][part] == 'None':
|
|
|
|
|
section[part] = None
|
|
|
|
|
else:
|
|
|
|
|
section[part] = parser[section_name][part]
|
2009-12-26 19:43:01 +00:00
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
section.update(parser[section_name])
|
2018-04-24 18:22:10 +00:00
|
|
|
|
except KeyError as ex:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('skipping missing section %s' % section_name)
|
2009-12-26 19:43:01 +00:00
|
|
|
|
|
|
|
|
|
self.loaded = True
|
2013-08-29 17:43:24 +00:00
|
|
|
|
|
|
|
|
|
def reload(self):
|
|
|
|
|
"""Force a reload of the base config"""
|
|
|
|
|
self.loaded = False
|
|
|
|
|
self.load()
|
2020-10-08 21:11:32 +00:00
|
|
|
|
|
2009-12-26 13:39:14 +00:00
|
|
|
|
def save(self):
|
|
|
|
|
"""Save the config to a file"""
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('saving config')
|
2020-04-05 15:00:27 +00:00
|
|
|
|
parser = ConfigObj(encoding='utf-8')
|
2009-12-26 13:39:14 +00:00
|
|
|
|
parser.indent_type = ' '
|
2009-12-26 19:43:01 +00:00
|
|
|
|
|
|
|
|
|
for section_name in ['global_config', 'keybindings']:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing section: %s' % section_name)
|
2009-12-26 13:39:14 +00:00
|
|
|
|
section = getattr(self, section_name)
|
|
|
|
|
parser[section_name] = dict_diff(DEFAULTS[section_name], section)
|
|
|
|
|
|
2020-09-24 10:39:42 +00:00
|
|
|
|
from .configjson import JSON_PROFILE_NAME, JSON_LAYOUT_NAME
|
|
|
|
|
|
2009-12-26 19:43:01 +00:00
|
|
|
|
parser['profiles'] = {}
|
|
|
|
|
for profile in self.profiles:
|
2020-09-24 10:39:42 +00:00
|
|
|
|
if profile == JSON_PROFILE_NAME:
|
|
|
|
|
continue
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing profile: %s' % profile)
|
2010-01-22 18:54:36 +00:00
|
|
|
|
parser['profiles'][profile] = dict_diff(
|
|
|
|
|
DEFAULTS['profiles']['default'], self.profiles[profile])
|
2009-12-26 19:43:01 +00:00
|
|
|
|
|
|
|
|
|
parser['layouts'] = {}
|
|
|
|
|
for layout in self.layouts:
|
2020-09-24 10:39:42 +00:00
|
|
|
|
if layout == JSON_LAYOUT_NAME:
|
|
|
|
|
continue
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing layout: %s' % layout)
|
2010-02-02 00:39:41 +00:00
|
|
|
|
parser['layouts'][layout] = self.layouts[layout]
|
2009-12-26 19:43:01 +00:00
|
|
|
|
|
|
|
|
|
parser['plugins'] = {}
|
|
|
|
|
for plugin in self.plugins:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Processing plugin: %s' % plugin)
|
2009-12-26 19:43:01 +00:00
|
|
|
|
parser['plugins'][plugin] = self.plugins[plugin]
|
|
|
|
|
|
2010-01-14 22:58:41 +00:00
|
|
|
|
config_dir = get_config_dir()
|
2010-01-15 23:32:16 +00:00
|
|
|
|
if not os.path.isdir(config_dir):
|
2010-01-14 22:58:41 +00:00
|
|
|
|
os.makedirs(config_dir)
|
2020-10-12 03:28:04 +00:00
|
|
|
|
|
2010-01-14 22:58:41 +00:00
|
|
|
|
try:
|
2020-12-01 19:38:29 +00:00
|
|
|
|
if self.command_line_options.config:
|
|
|
|
|
filename = self.command_line_options.config
|
|
|
|
|
else:
|
|
|
|
|
filename = os.path.join(config_dir,'config')
|
2020-10-12 03:28:04 +00:00
|
|
|
|
|
2020-12-01 19:38:29 +00:00
|
|
|
|
if not os.path.isfile(filename):
|
|
|
|
|
open(filename, 'a').close()
|
2020-10-08 21:11:32 +00:00
|
|
|
|
|
2020-12-01 19:38:29 +00:00
|
|
|
|
backup_file = filename + '~'
|
|
|
|
|
shutil.copy2(filename, backup_file)
|
2020-04-05 14:59:50 +00:00
|
|
|
|
|
2020-12-01 19:38:29 +00:00
|
|
|
|
with open(filename, 'wb') as fh:
|
2020-04-05 14:59:50 +00:00
|
|
|
|
parser.write(fh)
|
|
|
|
|
|
2020-10-12 03:16:46 +00:00
|
|
|
|
os.remove(backup_file)
|
2018-04-24 18:22:10 +00:00
|
|
|
|
except Exception as ex:
|
2010-01-14 22:58:41 +00:00
|
|
|
|
err('ConfigBase::save: Unable to save config: %s' % ex)
|
2009-12-22 00:24:53 +00:00
|
|
|
|
|
2015-02-25 23:02:09 +00:00
|
|
|
|
def get_item(self, key, profile='default', plugin=None, default=None):
|
2009-08-18 11:46:41 +00:00
|
|
|
|
"""Look up a configuration item"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if profile not in self.profiles:
|
2010-05-15 14:00:09 +00:00
|
|
|
|
# Hitting this generally implies a bug
|
|
|
|
|
profile = 'default'
|
|
|
|
|
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if key in self.global_config:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('%s found in globals: %s' %
|
2010-01-10 23:47:15 +00:00
|
|
|
|
(key, self.global_config[key]))
|
2009-12-22 00:24:53 +00:00
|
|
|
|
return(self.global_config[key])
|
2018-04-24 18:22:10 +00:00
|
|
|
|
elif key in self.profiles[profile]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('%s found in profile %s: %s' % (
|
2010-01-10 23:47:15 +00:00
|
|
|
|
key, profile, self.profiles[profile][key]))
|
2009-12-22 00:24:53 +00:00
|
|
|
|
return(self.profiles[profile][key])
|
|
|
|
|
elif key == 'keybindings':
|
|
|
|
|
return(self.keybindings)
|
2015-02-25 23:02:09 +00:00
|
|
|
|
elif plugin and plugin in self.plugins and key in self.plugins[plugin]:
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('%s found in plugin %s: %s' % (
|
2010-01-10 23:47:15 +00:00
|
|
|
|
key, plugin, self.plugins[plugin][key]))
|
2009-12-22 00:24:53 +00:00
|
|
|
|
return(self.plugins[plugin][key])
|
2015-02-25 23:02:09 +00:00
|
|
|
|
elif default:
|
|
|
|
|
return default
|
2009-12-22 00:24:53 +00:00
|
|
|
|
else:
|
|
|
|
|
raise KeyError('ConfigBase::get_item: unknown key %s' % key)
|
2008-03-08 00:04:41 +00:00
|
|
|
|
|
2009-12-23 00:10:57 +00:00
|
|
|
|
def set_item(self, key, value, profile='default', plugin=None):
|
|
|
|
|
"""Set a configuration item"""
|
2022-01-28 20:51:54 +00:00
|
|
|
|
dbg('Setting %s=%s (profile=%s, plugin=%s)' %
|
2009-12-23 00:10:57 +00:00
|
|
|
|
(key, value, profile, plugin))
|
|
|
|
|
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if key in self.global_config:
|
2009-12-23 00:10:57 +00:00
|
|
|
|
self.global_config[key] = value
|
2018-04-24 18:22:10 +00:00
|
|
|
|
elif key in self.profiles[profile]:
|
2009-12-26 19:43:01 +00:00
|
|
|
|
self.profiles[profile][key] = value
|
2009-12-23 00:10:57 +00:00
|
|
|
|
elif key == 'keybindings':
|
|
|
|
|
self.keybindings = value
|
2010-01-05 21:44:12 +00:00
|
|
|
|
elif plugin is not None:
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if plugin not in self.plugins:
|
2010-01-05 22:15:56 +00:00
|
|
|
|
self.plugins[plugin] = {}
|
2009-12-23 00:10:57 +00:00
|
|
|
|
self.plugins[plugin][key] = value
|
|
|
|
|
else:
|
|
|
|
|
raise KeyError('ConfigBase::set_item: unknown key %s' % key)
|
|
|
|
|
|
|
|
|
|
return(True)
|
|
|
|
|
|
2010-01-05 21:44:12 +00:00
|
|
|
|
def get_plugin(self, plugin):
|
|
|
|
|
"""Return a whole tree for a plugin"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if plugin in self.plugins:
|
2010-01-05 21:44:12 +00:00
|
|
|
|
return(self.plugins[plugin])
|
|
|
|
|
|
|
|
|
|
def set_plugin(self, plugin, tree):
|
|
|
|
|
"""Set a whole tree for a plugin"""
|
|
|
|
|
self.plugins[plugin] = tree
|
|
|
|
|
|
2011-12-28 22:00:52 +00:00
|
|
|
|
def del_plugin(self, plugin):
|
|
|
|
|
"""Delete a whole tree for a plugin"""
|
|
|
|
|
if plugin in self.plugins:
|
|
|
|
|
del self.plugins[plugin]
|
|
|
|
|
|
2021-08-30 15:55:42 +00:00
|
|
|
|
def add_profile(self, profile, toclone):
|
2010-01-09 15:51:56 +00:00
|
|
|
|
"""Add a new profile"""
|
|
|
|
|
if profile in self.profiles:
|
|
|
|
|
return(False)
|
2021-08-30 15:55:42 +00:00
|
|
|
|
if toclone is not None:
|
|
|
|
|
newprofile = copy(toclone)
|
|
|
|
|
else:
|
|
|
|
|
newprofile = copy(DEFAULTS['profiles']['default'])
|
|
|
|
|
self.profiles[profile] = newprofile
|
2010-01-09 15:51:56 +00:00
|
|
|
|
return(True)
|
|
|
|
|
|
2010-02-01 12:11:44 +00:00
|
|
|
|
def add_layout(self, name, layout):
|
2010-01-30 00:27:57 +00:00
|
|
|
|
"""Add a new layout"""
|
2010-02-01 12:11:44 +00:00
|
|
|
|
if name in self.layouts:
|
2010-01-30 00:27:57 +00:00
|
|
|
|
return(False)
|
2010-02-01 12:11:44 +00:00
|
|
|
|
self.layouts[name] = layout
|
2010-01-30 00:27:57 +00:00
|
|
|
|
return(True)
|
|
|
|
|
|
2014-05-19 19:47:11 +00:00
|
|
|
|
def replace_layout(self, name, layout):
|
|
|
|
|
"""Replaces a layout with the given name"""
|
|
|
|
|
if not name in self.layouts:
|
|
|
|
|
return(False)
|
|
|
|
|
self.layouts[name] = layout
|
|
|
|
|
return(True)
|
|
|
|
|
|
2010-02-01 12:11:44 +00:00
|
|
|
|
def get_layout(self, layout):
|
|
|
|
|
"""Return a layout"""
|
2018-04-24 18:22:10 +00:00
|
|
|
|
if layout in self.layouts:
|
2010-02-01 12:11:44 +00:00
|
|
|
|
return(self.layouts[layout])
|
|
|
|
|
else:
|
|
|
|
|
err('layout does not exist: %s' % layout)
|
|
|
|
|
|
|
|
|
|
def set_layout(self, layout, tree):
|
|
|
|
|
"""Set a layout"""
|
|
|
|
|
self.layouts[layout] = tree
|