blob: b94b8f1808502ee5a3782dff8927eb4c5f1a484d [file] [log] [blame]
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00001"""Provides access to stored IDLE configuration information.
Steven M. Gavac5976402002-01-04 03:06:08 +00002
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00003Refer to the comments at the beginning of config-main.def for a description of
4the available configuration files and the design implemented to update user
5configuration information. In particular, user configuration choices which
6duplicate the defaults will be removed from the user's configuration files,
Kurt B. Kaisere66675b2003-01-27 02:36:18 +00007and if a file becomes empty, it will be deleted.
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +00008
9The contents of the user files may be altered using the Options/Configure IDLE
10menu to access the configuration GUI (configDialog.py), or manually.
11
12Throughout this module there is an emphasis on returning useable defaults
13when a problem occurs in returning a requested configuration value back to
14idle. This is to allow IDLE to continue to function in spite of errors in
15the retrieval of config information. When a default is returned instead of
16a requested config value, a message is printed to stderr to aid in
17configuration problem notification and resolution.
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +000018"""
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040019# TODOs added Oct 2014, tjr
20
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +000021import os
22import sys
Guido van Rossum36e0a922007-07-20 04:05:57 +000023
Terry Jan Reedy44f09eb2014-07-01 18:52:37 -040024from configparser import ConfigParser
Steven M. Gavac11ccf32001-09-24 09:43:17 +000025
Neal Norwitz5b0b00f2002-11-30 19:10:19 +000026class InvalidConfigType(Exception): pass
27class InvalidConfigSet(Exception): pass
28class InvalidFgBg(Exception): pass
29class InvalidTheme(Exception): pass
30
Steven M. Gavac11ccf32001-09-24 09:43:17 +000031class IdleConfParser(ConfigParser):
32 """
33 A ConfigParser specialised for idle configuration file handling
34 """
35 def __init__(self, cfgFile, cfgDefaults=None):
36 """
37 cfgFile - string, fully specified configuration file name
38 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040039 self.file = cfgFile
Serhiy Storchaka89953002013-02-07 15:24:36 +020040 ConfigParser.__init__(self, defaults=cfgDefaults, strict=False)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000041
Thomas Wouterscf297e42007-02-23 15:07:44 +000042 def Get(self, section, option, type=None, default=None, raw=False):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000043 """
44 Get an option value for given section/option or return default.
45 If type is specified, return as type.
46 """
Terry Jan Reedya9421fb2014-10-22 20:15:18 -040047 # TODO Use default as fallback, at least if not None
48 # Should also print Warning(file, section, option).
49 # Currently may raise ValueError
Thomas Wouterscf297e42007-02-23 15:07:44 +000050 if not self.has_option(section, option):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000051 return default
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040052 if type == 'bool':
Thomas Wouterscf297e42007-02-23 15:07:44 +000053 return self.getboolean(section, option)
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040054 elif type == 'int':
Thomas Wouterscf297e42007-02-23 15:07:44 +000055 return self.getint(section, option)
56 else:
57 return self.get(section, option, raw=raw)
Steven M. Gavac11ccf32001-09-24 09:43:17 +000058
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040059 def GetOptionList(self, section):
60 "Return a list of options for given section, else []."
Steven M. Gava085eb1b2002-02-05 04:52:32 +000061 if self.has_section(section):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000062 return self.options(section)
63 else: #return a default value
64 return []
65
Steven M. Gavac11ccf32001-09-24 09:43:17 +000066 def Load(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040067 "Load the configuration file from disk."
Steven M. Gavac11ccf32001-09-24 09:43:17 +000068 self.read(self.file)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000069
Steven M. Gavac11ccf32001-09-24 09:43:17 +000070class IdleUserConfParser(IdleConfParser):
71 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000072 IdleConfigParser specialised for user configuration handling.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000073 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000074
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040075 def AddSection(self, section):
76 "If section doesn't exist, add it."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000077 if not self.has_section(section):
78 self.add_section(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000079
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000080 def RemoveEmptySections(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040081 "Remove any sections that have no options."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000082 for section in self.sections():
83 if not self.GetOptionList(section):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000084 self.remove_section(section)
85
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000086 def IsEmpty(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040087 "Return True if no sections after removing empty sections."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000088 self.RemoveEmptySections()
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040089 return not self.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000090
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040091 def RemoveOption(self, section, option):
92 """Return True if option is removed from section, else False.
93
94 False if either section does not exist or did not have option.
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000095 """
96 if self.has_section(section):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -040097 return self.remove_option(section, option)
98 return False
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000099
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400100 def SetOption(self, section, option, value):
101 """Return True if option is added or changed to value, else False.
102
103 Add section if required. False means option already had value.
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000104 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400105 if self.has_option(section, option):
106 if self.get(section, option) == value:
107 return False
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000108 else:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400109 self.set(section, option, value)
110 return True
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000111 else:
112 if not self.has_section(section):
113 self.add_section(section)
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400114 self.set(section, option, value)
115 return True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000116
Steven M. Gavab77d3432002-03-02 07:16:21 +0000117 def RemoveFile(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400118 "Remove user config file self.file from disk if it exists."
Steven M. Gavab77d3432002-03-02 07:16:21 +0000119 if os.path.exists(self.file):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000120 os.remove(self.file)
121
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000122 def Save(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000123 """Update user configuration file.
124
125 Remove empty sections. If resulting config isn't empty, write the file
126 to disk. If config is empty, remove the file from disk if it exists.
127
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000128 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000129 if not self.IsEmpty():
Christian Heimesbbffeb62008-01-24 09:42:52 +0000130 fname = self.file
131 try:
132 cfgFile = open(fname, 'w')
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200133 except OSError:
Christian Heimes0bd4e112008-02-12 22:59:25 +0000134 os.unlink(fname)
Christian Heimesbbffeb62008-01-24 09:42:52 +0000135 cfgFile = open(fname, 'w')
Amaury Forgeot d'Arcbbe7b0a2011-10-03 20:33:24 +0200136 with cfgFile:
137 self.write(cfgFile)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000138 else:
Steven M. Gavab77d3432002-03-02 07:16:21 +0000139 self.RemoveFile()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000140
141class IdleConf:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400142 """Hold config parsers for all idle config files in singleton instance.
143
144 Default config files, self.defaultCfg --
145 for config_type in self.config_types:
146 (idle install dir)/config-{config-type}.def
147
148 User config files, self.userCfg --
149 for config_type in self.config_types:
150 (user home dir)/.idlerc/config-{config-type}.cfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000151 """
152 def __init__(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400153 self.config_types = ('main', 'extensions', 'highlight', 'keys')
154 self.defaultCfg = {}
155 self.userCfg = {}
156 self.cfg = {} # TODO use to select userCfg vs defaultCfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000157 self.CreateConfigHandlers()
158 self.LoadCfgFiles()
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400159
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000160
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000161 def CreateConfigHandlers(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400162 "Populate default and user config parser dictionaries."
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000163 #build idle install path
164 if __name__ != '__main__': # we were imported
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000165 idleDir=os.path.dirname(__file__)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000166 else: # we were exec'ed (for testing only)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000167 idleDir=os.path.abspath(sys.path[0])
168 userDir=self.GetUserCfgDir()
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400169
170 defCfgFiles = {}
171 usrCfgFiles = {}
172 # TODO eliminate these temporaries by combining loops
173 for cfgType in self.config_types: #build config file names
174 defCfgFiles[cfgType] = os.path.join(
175 idleDir, 'config-' + cfgType + '.def')
176 usrCfgFiles[cfgType] = os.path.join(
177 userDir, 'config-' + cfgType + '.cfg')
178 for cfgType in self.config_types: #create config parsers
179 self.defaultCfg[cfgType] = IdleConfParser(defCfgFiles[cfgType])
180 self.userCfg[cfgType] = IdleUserConfParser(usrCfgFiles[cfgType])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000181
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000182 def GetUserCfgDir(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400183 """Return a filesystem directory for storing user config files.
Tim Peters608c2ff2005-01-13 17:37:38 +0000184
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400185 Creates it if required.
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000186 """
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000187 cfgDir = '.idlerc'
188 userDir = os.path.expanduser('~')
189 if userDir != '~': # expanduser() found user home dir
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000190 if not os.path.exists(userDir):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400191 warn = ('\n Warning: os.path.expanduser("~") points to\n ' +
192 userDir + ',\n but the path does not exist.')
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000193 try:
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400194 print(warn, file=sys.stderr)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200195 except OSError:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000196 pass
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000197 userDir = '~'
198 if userDir == "~": # still no path to home!
199 # traditionally IDLE has defaulted to os.getcwd(), is this adequate?
200 userDir = os.getcwd()
201 userDir = os.path.join(userDir, cfgDir)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000202 if not os.path.exists(userDir):
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000203 try:
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000204 os.mkdir(userDir)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200205 except OSError:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400206 warn = ('\n Warning: unable to create user config directory\n' +
207 userDir + '\n Check path and permissions.\n Exiting!\n')
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400208 print(warn, file=sys.stderr)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000209 raise SystemExit
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400210 # TODO continue without userDIr instead of exit
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000211 return userDir
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000212
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000213 def GetOption(self, configType, section, option, default=None, type=None,
Thomas Wouterscf297e42007-02-23 15:07:44 +0000214 warn_on_default=True, raw=False):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400215 """Return a value for configType section option, or default.
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000216
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400217 If type is not None, return a value of that type. Also pass raw
218 to the config parser. First try to return a valid value
219 (including type) from a user configuration. If that fails, try
220 the default configuration. If that fails, return default, with a
221 default of None.
222
223 Warn if either user or default configurations have an invalid value.
224 Warn if default is returned and warn_on_default is True.
Steven M. Gava429a86af2001-10-23 10:42:12 +0000225 """
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200226 try:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400227 if self.userCfg[configType].has_option(section, option):
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200228 return self.userCfg[configType].Get(section, option,
229 type=type, raw=raw)
230 except ValueError:
231 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
232 ' invalid %r value for configuration option %r\n'
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400233 ' from section %r: %r' %
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200234 (type, option, section,
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400235 self.userCfg[configType].Get(section, option, raw=raw)))
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200236 try:
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400237 print(warning, file=sys.stderr)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200238 except OSError:
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200239 pass
240 try:
241 if self.defaultCfg[configType].has_option(section,option):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400242 return self.defaultCfg[configType].Get(
243 section, option, type=type, raw=raw)
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200244 except ValueError:
245 pass
246 #returning default, print warning
247 if warn_on_default:
248 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
249 ' problem retrieving configuration option %r\n'
250 ' from section %r.\n'
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400251 ' returning default value: %r' %
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200252 (option, section, default))
253 try:
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400254 print(warning, file=sys.stderr)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200255 except OSError:
Andrew Svetlov8a495a42012-12-24 13:15:43 +0200256 pass
257 return default
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000259 def SetOption(self, configType, section, option, value):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400260 """Set section option to value in user config file."""
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000261 self.userCfg[configType].SetOption(section, option, value)
262
Steven M. Gava2a63a072001-10-26 06:50:54 +0000263 def GetSectionList(self, configSet, configType):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400264 """Return sections for configSet configType configuration.
265
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000266 configSet must be either 'user' or 'default'
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400267 configType must be in self.config_types.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000268 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400269 if not (configType in self.config_types):
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000270 raise InvalidConfigType('Invalid configType specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000271 if configSet == 'user':
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400272 cfgParser = self.userCfg[configType]
Steven M. Gava2a63a072001-10-26 06:50:54 +0000273 elif configSet == 'default':
274 cfgParser=self.defaultCfg[configType]
275 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000276 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000277 return cfgParser.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000278
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000279 def GetHighlight(self, theme, element, fgBg=None):
Terry Jan Reedy86757992014-10-09 18:44:32 -0400280 """Return individual theme element highlight color(s).
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400281
Terry Jan Reedy86757992014-10-09 18:44:32 -0400282 fgBg - string ('fg' or 'bg') or None.
283 If None, return a dictionary containing fg and bg colors with
284 keys 'foreground' and 'background'. Otherwise, only return
285 fg or bg color, as specified. Colors are intended to be
286 appropriate for passing to Tkinter in, e.g., a tag_config call).
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000287 """
Steven M. Gava9f25e672002-02-11 02:51:18 +0000288 if self.defaultCfg['highlight'].has_section(theme):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400289 themeDict = self.GetThemeDict('default', theme)
Steven M. Gava9f25e672002-02-11 02:51:18 +0000290 else:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400291 themeDict = self.GetThemeDict('user', theme)
292 fore = themeDict[element + '-foreground']
Terry Jan Reedy86757992014-10-09 18:44:32 -0400293 if element == 'cursor': # There is no config value for cursor bg
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400294 back = themeDict['normal-background']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000295 else:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400296 back = themeDict[element + '-background']
297 highlight = {"foreground": fore, "background": back}
Terry Jan Reedy86757992014-10-09 18:44:32 -0400298 if not fgBg: # Return dict of both colors
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000299 return highlight
Terry Jan Reedy86757992014-10-09 18:44:32 -0400300 else: # Return specified color only
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000301 if fgBg == 'fg':
302 return highlight["foreground"]
303 if fgBg == 'bg':
304 return highlight["background"]
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000305 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000306 raise InvalidFgBg('Invalid fgBg specified')
Steven M. Gava9f25e672002-02-11 02:51:18 +0000307
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400308 def GetThemeDict(self, type, themeName):
309 """Return {option:value} dict for elements in themeName.
310
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000311 type - string, 'default' or 'user' theme type
312 themeName - string, theme name
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400313 Values are loaded over ultimate fallback defaults to guarantee
314 that all theme elements are present in a newly created theme.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000315 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000316 if type == 'user':
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400317 cfgParser = self.userCfg['highlight']
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000318 elif type == 'default':
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400319 cfgParser = self.defaultCfg['highlight']
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000320 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000321 raise InvalidTheme('Invalid theme type specified')
Terry Jan Reedy86757992014-10-09 18:44:32 -0400322 # Provide foreground and background colors for each theme
323 # element (other than cursor) even though some values are not
324 # yet used by idle, to allow for their use in the future.
325 # Default values are generally black and white.
326 # TODO copy theme from a class attribute.
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400327 theme ={'normal-foreground':'#000000',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000328 'normal-background':'#ffffff',
329 'keyword-foreground':'#000000',
330 'keyword-background':'#ffffff',
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000331 'builtin-foreground':'#000000',
332 'builtin-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000333 'comment-foreground':'#000000',
334 'comment-background':'#ffffff',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000335 'string-foreground':'#000000',
336 'string-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000337 'definition-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000338 'definition-background':'#ffffff',
339 'hilite-foreground':'#000000',
340 'hilite-background':'gray',
341 'break-foreground':'#ffffff',
342 'break-background':'#000000',
343 'hit-foreground':'#ffffff',
344 'hit-background':'#000000',
345 'error-foreground':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000346 'error-background':'#000000',
347 #cursor (only foreground can be set)
348 'cursor-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000349 #shell window
350 'stdout-foreground':'#000000',
351 'stdout-background':'#ffffff',
352 'stderr-foreground':'#000000',
353 'stderr-background':'#ffffff',
354 'console-foreground':'#000000',
355 'console-background':'#ffffff' }
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000356 for element in theme:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400357 if not cfgParser.has_option(themeName, element):
Terry Jan Reedy86757992014-10-09 18:44:32 -0400358 # Print warning that will return a default color
359 warning = ('\n Warning: configHandler.IdleConf.GetThemeDict'
Walter Dörwald70a6b492004-02-12 17:35:32 +0000360 ' -\n problem retrieving theme element %r'
361 '\n from theme %r.\n'
Terry Jan Reedy86757992014-10-09 18:44:32 -0400362 ' returning default color: %r' %
Walter Dörwald70a6b492004-02-12 17:35:32 +0000363 (element, themeName, theme[element]))
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000364 try:
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400365 print(warning, file=sys.stderr)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200366 except OSError:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000367 pass
Terry Jan Reedy86757992014-10-09 18:44:32 -0400368 theme[element] = cfgParser.Get(
369 themeName, element, default=theme[element])
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000370 return theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000371
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000372 def CurrentTheme(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400373 "Return the name of the currently active theme."
374 return self.GetOption('main', 'Theme', 'name', default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000375
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000376 def CurrentKeys(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400377 "Return the name of the currently active key set."
378 return self.GetOption('main', 'Keys', 'name', default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000379
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000380 def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400381 """Return extensions in default and user config-extensions files.
382
383 If active_only True, only return active (enabled) extensions
384 and optionally only editor or shell extensions.
385 If active_only False, return all extensions.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000386 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400387 extns = self.RemoveKeyBindNames(
388 self.GetSectionList('default', 'extensions'))
389 userExtns = self.RemoveKeyBindNames(
390 self.GetSectionList('user', 'extensions'))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000391 for extn in userExtns:
392 if extn not in extns: #user has added own extension
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000393 extns.append(extn)
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000394 if active_only:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400395 activeExtns = []
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000396 for extn in extns:
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000397 if self.GetOption('extensions', extn, 'enable', default=True,
398 type='bool'):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000399 #the extension is enabled
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400400 if editor_only or shell_only: # TODO if both, contradictory
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000401 if editor_only:
402 option = "enable_editor"
403 else:
404 option = "enable_shell"
405 if self.GetOption('extensions', extn,option,
406 default=True, type='bool',
407 warn_on_default=False):
408 activeExtns.append(extn)
409 else:
410 activeExtns.append(extn)
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000411 return activeExtns
412 else:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000413 return extns
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000414
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400415 def RemoveKeyBindNames(self, extnNameList):
416 "Return extnNameList with keybinding section names removed."
417 # TODO Easier to return filtered copy with list comp
418 names = extnNameList
419 kbNameIndicies = []
Steven M. Gavac628a062002-01-19 10:33:21 +0000420 for name in names:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000421 if name.endswith(('_bindings', '_cfgBindings')):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000422 kbNameIndicies.append(names.index(name))
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400423 kbNameIndicies.sort(reverse=True)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000424 for index in kbNameIndicies: #delete each keybinding section name
Steven M. Gavac628a062002-01-19 10:33:21 +0000425 del(names[index])
426 return names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000427
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400428 def GetExtnNameForEvent(self, virtualEvent):
429 """Return the name of the extension binding virtualEvent, or None.
430
431 virtualEvent - string, name of the virtual event to test for,
432 without the enclosing '<< >>'
Steven M. Gavaa498af22002-02-01 01:33:36 +0000433 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400434 extName = None
435 vEvent = '<<' + virtualEvent + '>>'
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000436 for extn in self.GetExtensions(active_only=0):
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000437 for event in self.GetExtensionKeys(extn):
Steven M. Gavaa498af22002-02-01 01:33:36 +0000438 if event == vEvent:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400439 extName = extn # TODO return here?
Steven M. Gavaa498af22002-02-01 01:33:36 +0000440 return extName
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000441
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400442 def GetExtensionKeys(self, extensionName):
443 """Return dict: {configurable extensionName event : active keybinding}.
444
445 Events come from default config extension_cfgBindings section.
446 Keybindings come from GetCurrentKeySet() active key dict,
447 where previously used bindings are disabled.
Steven M. Gavac628a062002-01-19 10:33:21 +0000448 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400449 keysName = extensionName + '_cfgBindings'
450 activeKeys = self.GetCurrentKeySet()
451 extKeys = {}
Steven M. Gavac628a062002-01-19 10:33:21 +0000452 if self.defaultCfg['extensions'].has_section(keysName):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400453 eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000454 for eventName in eventNames:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400455 event = '<<' + eventName + '>>'
456 binding = activeKeys[event]
457 extKeys[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000458 return extKeys
459
Steven M. Gavac628a062002-01-19 10:33:21 +0000460 def __GetRawExtensionKeys(self,extensionName):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400461 """Return dict {configurable extensionName event : keybinding list}.
462
463 Events come from default config extension_cfgBindings section.
464 Keybindings list come from the splitting of GetOption, which
465 tries user config before default config.
Steven M. Gavac628a062002-01-19 10:33:21 +0000466 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400467 keysName = extensionName+'_cfgBindings'
468 extKeys = {}
Steven M. Gavac628a062002-01-19 10:33:21 +0000469 if self.defaultCfg['extensions'].has_section(keysName):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400470 eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000471 for eventName in eventNames:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400472 binding = self.GetOption(
473 'extensions', keysName, eventName, default='').split()
474 event = '<<' + eventName + '>>'
475 extKeys[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000476 return extKeys
477
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400478 def GetExtensionBindings(self, extensionName):
479 """Return dict {extensionName event : active or defined keybinding}.
480
481 Augment self.GetExtensionKeys(extensionName) with mapping of non-
482 configurable events (from default config) to GetOption splits,
483 as in self.__GetRawExtensionKeys.
Steven M. Gavac628a062002-01-19 10:33:21 +0000484 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400485 bindsName = extensionName + '_bindings'
486 extBinds = self.GetExtensionKeys(extensionName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000487 #add the non-configurable bindings
488 if self.defaultCfg['extensions'].has_section(bindsName):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400489 eventNames = self.defaultCfg['extensions'].GetOptionList(bindsName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000490 for eventName in eventNames:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400491 binding = self.GetOption(
492 'extensions', bindsName, eventName, default='').split()
493 event = '<<' + eventName + '>>'
494 extBinds[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000495
496 return extBinds
497
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000498 def GetKeyBinding(self, keySetName, eventStr):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400499 """Return the keybinding list for keySetName eventStr.
500
501 keySetName - name of key binding set (config-keys section).
502 eventStr - virtual event, including brackets, as in '<<event>>'.
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000503 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400504 eventName = eventStr[2:-2] #trim off the angle brackets
505 binding = self.GetOption('keys', keySetName, eventName, default='').split()
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000506 return binding
507
Steven M. Gavac628a062002-01-19 10:33:21 +0000508 def GetCurrentKeySet(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400509 "Return CurrentKeys with 'darwin' modifications."
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000510 result = self.GetKeySet(self.CurrentKeys())
511
Ned Deilyb7601672014-03-27 20:49:14 -0700512 if sys.platform == "darwin":
513 # OS X Tk variants do not support the "Alt" keyboard modifier.
514 # So replace all keybingings that use "Alt" with ones that
515 # use the "Option" keyboard modifier.
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400516 # TODO (Ned?): the "Option" modifier does not work properly for
Ned Deilyb7601672014-03-27 20:49:14 -0700517 # Cocoa Tk and XQuartz Tk so we should not use it
518 # in default OS X KeySets.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000519 for k, v in result.items():
520 v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
521 if v != v2:
522 result[k] = v2
523
524 return result
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000525
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400526 def GetKeySet(self, keySetName):
527 """Return event-key dict for keySetName core plus active extensions.
528
529 If a binding defined in an extension is already in use, the
530 extension binding is disabled by being set to ''
Steven M. Gava2a63a072001-10-26 06:50:54 +0000531 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400532 keySet = self.GetCoreKeys(keySetName)
533 activeExtns = self.GetExtensions(active_only=1)
Steven M. Gavac628a062002-01-19 10:33:21 +0000534 for extn in activeExtns:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400535 extKeys = self.__GetRawExtensionKeys(extn)
Steven M. Gavac628a062002-01-19 10:33:21 +0000536 if extKeys: #the extension defines keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000537 for event in extKeys:
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000538 if extKeys[event] in keySet.values():
Steven M. Gavac628a062002-01-19 10:33:21 +0000539 #the binding is already in use
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400540 extKeys[event] = '' #disable this binding
541 keySet[event] = extKeys[event] #add binding
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000542 return keySet
543
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400544 def IsCoreBinding(self, virtualEvent):
545 """Return True if the virtual event is one of the core idle key events.
546
547 virtualEvent - string, name of the virtual event to test for,
548 without the enclosing '<< >>'
Steven M. Gavaa498af22002-02-01 01:33:36 +0000549 """
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000550 return ('<<'+virtualEvent+'>>') in self.GetCoreKeys()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000551
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400552# TODO make keyBindins a file or class attribute used for test above
553# and copied in function below
554
Steven M. Gavac628a062002-01-19 10:33:21 +0000555 def GetCoreKeys(self, keySetName=None):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400556 """Return dict of core virtual-key keybindings for keySetName.
557
558 The default keySetName None corresponds to the keyBindings base
559 dict. If keySetName is not None, bindings from the config
560 file(s) are loaded _over_ these defaults, so if there is a
561 problem getting any core binding there will be an 'ultimate last
562 resort fallback' to the CUA-ish bindings defined here.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000563 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000564 keyBindings={
Steven M. Gavaa498af22002-02-01 01:33:36 +0000565 '<<copy>>': ['<Control-c>', '<Control-C>'],
566 '<<cut>>': ['<Control-x>', '<Control-X>'],
567 '<<paste>>': ['<Control-v>', '<Control-V>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000568 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
569 '<<center-insert>>': ['<Control-l>'],
570 '<<close-all-windows>>': ['<Control-q>'],
571 '<<close-window>>': ['<Alt-F4>'],
Kurt B. Kaiser84f48032002-09-26 22:13:22 +0000572 '<<do-nothing>>': ['<Control-x>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000573 '<<end-of-file>>': ['<Control-d>'],
574 '<<python-docs>>': ['<F1>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000575 '<<python-context-help>>': ['<Shift-F1>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000576 '<<history-next>>': ['<Alt-n>'],
577 '<<history-previous>>': ['<Alt-p>'],
578 '<<interrupt-execution>>': ['<Control-c>'],
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000579 '<<view-restart>>': ['<F6>'],
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000580 '<<restart-shell>>': ['<Control-F6>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000581 '<<open-class-browser>>': ['<Alt-c>'],
582 '<<open-module>>': ['<Alt-m>'],
583 '<<open-new-window>>': ['<Control-n>'],
584 '<<open-window-from-file>>': ['<Control-o>'],
585 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000586 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000587 '<<redo>>': ['<Control-y>'],
588 '<<remove-selection>>': ['<Escape>'],
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +0000589 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000590 '<<save-window-as-file>>': ['<Alt-s>'],
591 '<<save-window>>': ['<Control-s>'],
592 '<<select-all>>': ['<Alt-a>'],
593 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000594 '<<undo>>': ['<Control-z>'],
595 '<<find-again>>': ['<Control-g>', '<F3>'],
596 '<<find-in-files>>': ['<Alt-F3>'],
597 '<<find-selection>>': ['<Control-F3>'],
598 '<<find>>': ['<Control-f>'],
599 '<<replace>>': ['<Control-h>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000600 '<<goto-line>>': ['<Alt-g>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000601 '<<smart-backspace>>': ['<Key-BackSpace>'],
Andrew Svetlov67ac0792012-03-29 19:01:28 +0300602 '<<newline-and-indent>>': ['<Key-Return>', '<Key-KP_Enter>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000603 '<<smart-indent>>': ['<Key-Tab>'],
604 '<<indent-region>>': ['<Control-Key-bracketright>'],
605 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
606 '<<comment-region>>': ['<Alt-Key-3>'],
607 '<<uncomment-region>>': ['<Alt-Key-4>'],
608 '<<tabify-region>>': ['<Alt-Key-5>'],
609 '<<untabify-region>>': ['<Alt-Key-6>'],
610 '<<toggle-tabs>>': ['<Alt-Key-t>'],
Kurt B. Kaiser3069dbb2005-01-28 00:16:16 +0000611 '<<change-indentwidth>>': ['<Alt-Key-u>'],
612 '<<del-word-left>>': ['<Control-Key-BackSpace>'],
613 '<<del-word-right>>': ['<Control-Key-Delete>']
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000614 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000615 if keySetName:
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000616 for event in keyBindings:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400617 binding = self.GetKeyBinding(keySetName, event)
Steven M. Gava49745752002-02-18 01:43:11 +0000618 if binding:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400619 keyBindings[event] = binding
Steven M. Gava49745752002-02-18 01:43:11 +0000620 else: #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000621 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
622 ' -\n problem retrieving key binding for event %r'
623 '\n from key set %r.\n'
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400624 ' returning default value: %r' %
Walter Dörwald70a6b492004-02-12 17:35:32 +0000625 (event, keySetName, keyBindings[event]))
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000626 try:
Terry Jan Reedy81b062f2014-09-19 22:38:41 -0400627 print(warning, file=sys.stderr)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200628 except OSError:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000629 pass
Steven M. Gava17d01542001-12-03 00:37:28 +0000630 return keyBindings
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000631
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400632 def GetExtraHelpSourceList(self, configSet):
633 """Return list of extra help sources from a given configSet.
Kurt B. Kaisere66675b2003-01-27 02:36:18 +0000634
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000635 Valid configSets are 'user' or 'default'. Return a list of tuples of
636 the form (menu_item , path_to_help_file , option), or return the empty
637 list. 'option' is the sequence number of the help resource. 'option'
638 values determine the position of the menu items on the Help menu,
639 therefore the returned list must be sorted by 'option'.
640
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000641 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400642 helpSources = []
643 if configSet == 'user':
644 cfgParser = self.userCfg['main']
645 elif configSet == 'default':
646 cfgParser = self.defaultCfg['main']
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000647 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000648 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000649 options=cfgParser.GetOptionList('HelpFiles')
650 for option in options:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400651 value=cfgParser.Get('HelpFiles', option, default=';')
652 if value.find(';') == -1: #malformed config entry with no ';'
653 menuItem = '' #make these empty
654 helpPath = '' #so value won't be added to list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000655 else: #config entry contains ';' as expected
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000656 value=value.split(';')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000657 menuItem=value[0].strip()
658 helpPath=value[1].strip()
659 if menuItem and helpPath: #neither are empty strings
660 helpSources.append( (menuItem,helpPath,option) )
Kurt B. Kaiser4718bf82008-02-12 21:34:12 +0000661 helpSources.sort(key=lambda x: x[2])
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000662 return helpSources
663
664 def GetAllExtraHelpSourcesList(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400665 """Return a list of the details of all additional help sources.
666
667 Tuples in the list are those of GetExtraHelpSourceList.
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000668 """
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400669 allHelpSources = (self.GetExtraHelpSourceList('default') +
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000670 self.GetExtraHelpSourceList('user') )
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000671 return allHelpSources
672
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000673 def LoadCfgFiles(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400674 "Load all configuration files."
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000675 for key in self.defaultCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000676 self.defaultCfg[key].Load()
677 self.userCfg[key].Load() #same keys
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000678
679 def SaveUserCfgFiles(self):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400680 "Write all loaded user configuration files to disk."
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000681 for key in self.userCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000682 self.userCfg[key].Save()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000683
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000684
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400685idleConf = IdleConf()
686
687# TODO Revise test output, write expanded unittest
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000688### module test
689if __name__ == '__main__':
690 def dumpCfg(cfg):
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400691 print('\n', cfg, '\n')
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000692 for key in cfg:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400693 sections = cfg[key].sections()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000694 print(key)
695 print(sections)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000696 for section in sections:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400697 options = cfg[key].options(section)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000698 print(section)
699 print(options)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000700 for option in options:
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400701 print(option, '=', cfg[key].Get(section, option))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000702 dumpCfg(idleConf.defaultCfg)
703 dumpCfg(idleConf.userCfg)
Terry Jan Reedydeb7bf12014-10-06 23:26:26 -0400704 print(idleConf.userCfg['main'].Get('Theme', 'name'))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000705 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')