blob: 9822936c8cce418e293c218f21ad9ab5f619e9ff [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 Reedy163d7fb2014-10-06 23:26:17 -040019# TODOs added Oct 2014, tjr
20
Terry Jan Reedybee003c2014-09-19 22:37:24 -040021from __future__ import print_function
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +000022import os
23import sys
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -040024
Terry Jan Reedy9bc50562014-07-01 18:52:31 -040025from ConfigParser import ConfigParser
Steven M. Gavac11ccf32001-09-24 09:43:17 +000026
Neal Norwitz5b0b00f2002-11-30 19:10:19 +000027class InvalidConfigType(Exception): pass
28class InvalidConfigSet(Exception): pass
29class InvalidFgBg(Exception): pass
30class InvalidTheme(Exception): pass
31
Steven M. Gavac11ccf32001-09-24 09:43:17 +000032class IdleConfParser(ConfigParser):
33 """
34 A ConfigParser specialised for idle configuration file handling
35 """
36 def __init__(self, cfgFile, cfgDefaults=None):
37 """
38 cfgFile - string, fully specified configuration file name
39 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040040 self.file = cfgFile
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -040041 ConfigParser.__init__(self, defaults=cfgDefaults)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000042
Kurt B. Kaiser90f84922007-02-05 06:03:18 +000043 def Get(self, section, option, type=None, default=None, raw=False):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000044 """
45 Get an option value for given section/option or return default.
46 If type is specified, return as type.
47 """
Kurt B. Kaiser90f84922007-02-05 06:03:18 +000048 if not self.has_option(section, option):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000049 return default
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040050 if type == 'bool':
Kurt B. Kaiser90f84922007-02-05 06:03:18 +000051 return self.getboolean(section, option)
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040052 elif type == 'int':
Kurt B. Kaiser90f84922007-02-05 06:03:18 +000053 return self.getint(section, option)
54 else:
55 return self.get(section, option, raw=raw)
Steven M. Gavac11ccf32001-09-24 09:43:17 +000056
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040057 def GetOptionList(self, section):
58 "Return a list of options for given section, else []."
Steven M. Gava085eb1b2002-02-05 04:52:32 +000059 if self.has_section(section):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000060 return self.options(section)
61 else: #return a default value
62 return []
63
Steven M. Gavac11ccf32001-09-24 09:43:17 +000064 def Load(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040065 "Load the configuration file from disk."
Steven M. Gavac11ccf32001-09-24 09:43:17 +000066 self.read(self.file)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000067
Steven M. Gavac11ccf32001-09-24 09:43:17 +000068class IdleUserConfParser(IdleConfParser):
69 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000070 IdleConfigParser specialised for user configuration handling.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000071 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000072
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040073 def AddSection(self, section):
74 "If section doesn't exist, add it."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000075 if not self.has_section(section):
76 self.add_section(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000077
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000078 def RemoveEmptySections(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040079 "Remove any sections that have no options."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000080 for section in self.sections():
81 if not self.GetOptionList(section):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000082 self.remove_section(section)
83
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000084 def IsEmpty(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040085 "Return True if no sections after removing empty sections."
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000086 self.RemoveEmptySections()
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040087 return not self.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000088
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040089 def RemoveOption(self, section, option):
90 """Return True if option is removed from section, else False.
91
92 False if either section does not exist or did not have option.
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000093 """
94 if self.has_section(section):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040095 return self.remove_option(section, option)
96 return False
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000097
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -040098 def SetOption(self, section, option, value):
99 """Return True if option is added or changed to value, else False.
100
101 Add section if required. False means option already had value.
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000102 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400103 if self.has_option(section, option):
104 if self.get(section, option) == value:
105 return False
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000106 else:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400107 self.set(section, option, value)
108 return True
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000109 else:
110 if not self.has_section(section):
111 self.add_section(section)
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400112 self.set(section, option, value)
113 return True
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000114
Steven M. Gavab77d3432002-03-02 07:16:21 +0000115 def RemoveFile(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400116 "Remove user config file self.file from disk if it exists."
Steven M. Gavab77d3432002-03-02 07:16:21 +0000117 if os.path.exists(self.file):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000118 os.remove(self.file)
119
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000120 def Save(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000121 """Update user configuration file.
122
123 Remove empty sections. If resulting config isn't empty, write the file
124 to disk. If config is empty, remove the file from disk if it exists.
125
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000126 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000127 if not self.IsEmpty():
Kurt B. Kaiserb4aaa762008-01-23 22:19:23 +0000128 fname = self.file
129 try:
130 cfgFile = open(fname, 'w')
131 except IOError:
Kurt B. Kaiser8d365c32008-02-12 15:45:50 +0000132 os.unlink(fname)
Kurt B. Kaiserb4aaa762008-01-23 22:19:23 +0000133 cfgFile = open(fname, 'w')
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400134 with cfgFile:
135 self.write(cfgFile)
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000136 else:
Steven M. Gavab77d3432002-03-02 07:16:21 +0000137 self.RemoveFile()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000138
139class IdleConf:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400140 """Hold config parsers for all idle config files in singleton instance.
141
142 Default config files, self.defaultCfg --
143 for config_type in self.config_types:
144 (idle install dir)/config-{config-type}.def
145
146 User config files, self.userCfg --
147 for config_type in self.config_types:
148 (user home dir)/.idlerc/config-{config-type}.cfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000149 """
150 def __init__(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400151 self.config_types = ('main', 'extensions', 'highlight', 'keys')
152 self.defaultCfg = {}
153 self.userCfg = {}
154 self.cfg = {} # TODO use to select userCfg vs defaultCfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000155 self.CreateConfigHandlers()
156 self.LoadCfgFiles()
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400157
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000158
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000159 def CreateConfigHandlers(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400160 "Populate default and user config parser dictionaries."
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000161 #build idle install path
162 if __name__ != '__main__': # we were imported
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000163 idleDir=os.path.dirname(__file__)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000164 else: # we were exec'ed (for testing only)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000165 idleDir=os.path.abspath(sys.path[0])
166 userDir=self.GetUserCfgDir()
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400167
168 defCfgFiles = {}
169 usrCfgFiles = {}
170 # TODO eliminate these temporaries by combining loops
171 for cfgType in self.config_types: #build config file names
172 defCfgFiles[cfgType] = os.path.join(
173 idleDir, 'config-' + cfgType + '.def')
174 usrCfgFiles[cfgType] = os.path.join(
175 userDir, 'config-' + cfgType + '.cfg')
176 for cfgType in self.config_types: #create config parsers
177 self.defaultCfg[cfgType] = IdleConfParser(defCfgFiles[cfgType])
178 self.userCfg[cfgType] = IdleUserConfParser(usrCfgFiles[cfgType])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000179
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000180 def GetUserCfgDir(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400181 """Return a filesystem directory for storing user config files.
Tim Peters608c2ff2005-01-13 17:37:38 +0000182
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400183 Creates it if required.
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000184 """
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000185 cfgDir = '.idlerc'
186 userDir = os.path.expanduser('~')
187 if userDir != '~': # expanduser() found user home dir
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000188 if not os.path.exists(userDir):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400189 warn = ('\n Warning: os.path.expanduser("~") points to\n ' +
190 userDir + ',\n but the path does not exist.')
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000191 try:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400192 print(warn, file=sys.stderr)
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000193 except IOError:
194 pass
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000195 userDir = '~'
196 if userDir == "~": # still no path to home!
197 # traditionally IDLE has defaulted to os.getcwd(), is this adequate?
198 userDir = os.getcwd()
199 userDir = os.path.join(userDir, cfgDir)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000200 if not os.path.exists(userDir):
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000201 try:
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000202 os.mkdir(userDir)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000203 except (OSError, IOError):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400204 warn = ('\n Warning: unable to create user config directory\n' +
205 userDir + '\n Check path and permissions.\n Exiting!\n')
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400206 print(warn, file=sys.stderr)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000207 raise SystemExit
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400208 # TODO continue without userDIr instead of exit
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000209 return userDir
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000210
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000211 def GetOption(self, configType, section, option, default=None, type=None,
Kurt B. Kaiser90f84922007-02-05 06:03:18 +0000212 warn_on_default=True, raw=False):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400213 """Return a value for configType section option, or default.
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000214
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400215 If type is not None, return a value of that type. Also pass raw
216 to the config parser. First try to return a valid value
217 (including type) from a user configuration. If that fails, try
218 the default configuration. If that fails, return default, with a
219 default of None.
220
221 Warn if either user or default configurations have an invalid value.
222 Warn if default is returned and warn_on_default is True.
Steven M. Gava429a86a2001-10-23 10:42:12 +0000223 """
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200224 try:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400225 if self.userCfg[configType].has_option(section, option):
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200226 return self.userCfg[configType].Get(section, option,
227 type=type, raw=raw)
228 except ValueError:
229 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
230 ' invalid %r value for configuration option %r\n'
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400231 ' from section %r: %r' %
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200232 (type, option, section,
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400233 self.userCfg[configType].Get(section, option, raw=raw)))
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200234 try:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400235 print(warning, file=sys.stderr)
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200236 except IOError:
237 pass
238 try:
239 if self.defaultCfg[configType].has_option(section,option):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400240 return self.defaultCfg[configType].Get(
241 section, option, type=type, raw=raw)
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200242 except ValueError:
243 pass
244 #returning default, print warning
245 if warn_on_default:
246 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
247 ' problem retrieving configuration option %r\n'
248 ' from section %r.\n'
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400249 ' returning default value: %r' %
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200250 (option, section, default))
251 try:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400252 print(warning, file=sys.stderr)
Andrew Svetlovd8590ff2012-12-24 13:17:59 +0200253 except IOError:
254 pass
255 return default
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000256
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000257 def SetOption(self, configType, section, option, value):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400258 """Set section option to value in user config file."""
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000259 self.userCfg[configType].SetOption(section, option, value)
260
Steven M. Gava2a63a072001-10-26 06:50:54 +0000261 def GetSectionList(self, configSet, configType):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400262 """Return sections for configSet configType configuration.
263
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000264 configSet must be either 'user' or 'default'
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400265 configType must be in self.config_types.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000266 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400267 if not (configType in self.config_types):
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400268 raise InvalidConfigType('Invalid configType specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000269 if configSet == 'user':
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400270 cfgParser = self.userCfg[configType]
Steven M. Gava2a63a072001-10-26 06:50:54 +0000271 elif configSet == 'default':
272 cfgParser=self.defaultCfg[configType]
273 else:
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400274 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000275 return cfgParser.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000276
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000277 def GetHighlight(self, theme, element, fgBg=None):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400278 """Return individual highlighting theme elements.
279
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000280 fgBg - string ('fg'or'bg') or None, if None return a dictionary
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000281 containing fg and bg colours (appropriate for passing to Tkinter in,
282 e.g., a tag_config call), otherwise fg or bg colour only as specified.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000283 """
Steven M. Gava9f25e672002-02-11 02:51:18 +0000284 if self.defaultCfg['highlight'].has_section(theme):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400285 themeDict = self.GetThemeDict('default', theme)
Steven M. Gava9f25e672002-02-11 02:51:18 +0000286 else:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400287 themeDict = self.GetThemeDict('user', theme)
288 fore = themeDict[element + '-foreground']
289 if element == 'cursor': #there is no config value for cursor bg
290 back = themeDict['normal-background']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000291 else:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400292 back = themeDict[element + '-background']
293 highlight = {"foreground": fore, "background": back}
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000294 if not fgBg: #return dict of both colours
295 return highlight
296 else: #return specified colour only
297 if fgBg == 'fg':
298 return highlight["foreground"]
299 if fgBg == 'bg':
300 return highlight["background"]
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000301 else:
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400302 raise InvalidFgBg('Invalid fgBg specified')
Steven M. Gava9f25e672002-02-11 02:51:18 +0000303
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400304 def GetThemeDict(self, type, themeName):
305 """Return {option:value} dict for elements in themeName.
306
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000307 type - string, 'default' or 'user' theme type
308 themeName - string, theme name
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400309 Values are loaded over ultimate fallback defaults to guarantee
310 that all theme elements are present in a newly created theme.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000311 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000312 if type == 'user':
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400313 cfgParser = self.userCfg['highlight']
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000314 elif type == 'default':
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400315 cfgParser = self.defaultCfg['highlight']
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000316 else:
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400317 raise InvalidTheme('Invalid theme type specified')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000318 #foreground and background values are provded for each theme element
319 #(apart from cursor) even though all these values are not yet used
320 #by idle, to allow for their use in the future. Default values are
321 #generally black and white.
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400322 # TODO make theme, a constant, a module or class attribute
323 theme ={'normal-foreground':'#000000',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000324 'normal-background':'#ffffff',
325 'keyword-foreground':'#000000',
326 'keyword-background':'#ffffff',
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000327 'builtin-foreground':'#000000',
328 'builtin-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000329 'comment-foreground':'#000000',
330 'comment-background':'#ffffff',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000331 'string-foreground':'#000000',
332 'string-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000333 'definition-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000334 'definition-background':'#ffffff',
335 'hilite-foreground':'#000000',
336 'hilite-background':'gray',
337 'break-foreground':'#ffffff',
338 'break-background':'#000000',
339 'hit-foreground':'#ffffff',
340 'hit-background':'#000000',
341 'error-foreground':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000342 'error-background':'#000000',
343 #cursor (only foreground can be set)
344 'cursor-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000345 #shell window
346 'stdout-foreground':'#000000',
347 'stdout-background':'#ffffff',
348 'stderr-foreground':'#000000',
349 'stderr-background':'#ffffff',
350 'console-foreground':'#000000',
351 'console-background':'#ffffff' }
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400352 for element in theme:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400353 if not cfgParser.has_option(themeName, element):
Steven M. Gava052937f2002-02-11 02:20:53 +0000354 #we are going to return a default, print warning
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400355 warning = ('\n Warning: configHandler.py - IdleConf.GetThemeDict'
Walter Dörwald70a6b492004-02-12 17:35:32 +0000356 ' -\n problem retrieving theme element %r'
357 '\n from theme %r.\n'
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400358 ' returning default value: %r' %
Walter Dörwald70a6b492004-02-12 17:35:32 +0000359 (element, themeName, theme[element]))
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000360 try:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400361 print(warning, file=sys.stderr)
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000362 except IOError:
363 pass
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400364 colour = cfgParser.Get(themeName, element, default=theme[element])
365 theme[element] = colour
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000366 return theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000367
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000368 def CurrentTheme(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400369 "Return the name of the currently active theme."
370 return self.GetOption('main', 'Theme', 'name', default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000371
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000372 def CurrentKeys(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400373 "Return the name of the currently active key set."
374 return self.GetOption('main', 'Keys', 'name', default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000375
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000376 def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400377 """Return extensions in default and user config-extensions files.
378
379 If active_only True, only return active (enabled) extensions
380 and optionally only editor or shell extensions.
381 If active_only False, return all extensions.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000382 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400383 extns = self.RemoveKeyBindNames(
384 self.GetSectionList('default', 'extensions'))
385 userExtns = self.RemoveKeyBindNames(
386 self.GetSectionList('user', 'extensions'))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000387 for extn in userExtns:
388 if extn not in extns: #user has added own extension
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000389 extns.append(extn)
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000390 if active_only:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400391 activeExtns = []
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000392 for extn in extns:
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000393 if self.GetOption('extensions', extn, 'enable', default=True,
394 type='bool'):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000395 #the extension is enabled
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400396 if editor_only or shell_only: # TODO if both, contradictory
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000397 if editor_only:
398 option = "enable_editor"
399 else:
400 option = "enable_shell"
401 if self.GetOption('extensions', extn,option,
402 default=True, type='bool',
403 warn_on_default=False):
404 activeExtns.append(extn)
405 else:
406 activeExtns.append(extn)
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000407 return activeExtns
408 else:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000409 return extns
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000410
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400411 def RemoveKeyBindNames(self, extnNameList):
412 "Return extnNameList with keybinding section names removed."
413 # TODO Easier to return filtered copy with list comp
414 names = extnNameList
415 kbNameIndicies = []
Steven M. Gavac628a062002-01-19 10:33:21 +0000416 for name in names:
Georg Brandlb2afe852006-06-09 20:43:48 +0000417 if name.endswith(('_bindings', '_cfgBindings')):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000418 kbNameIndicies.append(names.index(name))
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400419 kbNameIndicies.sort(reverse=True)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000420 for index in kbNameIndicies: #delete each keybinding section name
Steven M. Gavac628a062002-01-19 10:33:21 +0000421 del(names[index])
422 return names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000423
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400424 def GetExtnNameForEvent(self, virtualEvent):
425 """Return the name of the extension binding virtualEvent, or None.
426
427 virtualEvent - string, name of the virtual event to test for,
428 without the enclosing '<< >>'
Steven M. Gavaa498af22002-02-01 01:33:36 +0000429 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400430 extName = None
431 vEvent = '<<' + virtualEvent + '>>'
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000432 for extn in self.GetExtensions(active_only=0):
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400433 for event in self.GetExtensionKeys(extn):
Steven M. Gavaa498af22002-02-01 01:33:36 +0000434 if event == vEvent:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400435 extName = extn # TODO return here?
Steven M. Gavaa498af22002-02-01 01:33:36 +0000436 return extName
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000437
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400438 def GetExtensionKeys(self, extensionName):
439 """Return dict: {configurable extensionName event : active keybinding}.
440
441 Events come from default config extension_cfgBindings section.
442 Keybindings come from GetCurrentKeySet() active key dict,
443 where previously used bindings are disabled.
Steven M. Gavac628a062002-01-19 10:33:21 +0000444 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400445 keysName = extensionName + '_cfgBindings'
446 activeKeys = self.GetCurrentKeySet()
447 extKeys = {}
Steven M. Gavac628a062002-01-19 10:33:21 +0000448 if self.defaultCfg['extensions'].has_section(keysName):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400449 eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000450 for eventName in eventNames:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400451 event = '<<' + eventName + '>>'
452 binding = activeKeys[event]
453 extKeys[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000454 return extKeys
455
Steven M. Gavac628a062002-01-19 10:33:21 +0000456 def __GetRawExtensionKeys(self,extensionName):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400457 """Return dict {configurable extensionName event : keybinding list}.
458
459 Events come from default config extension_cfgBindings section.
460 Keybindings list come from the splitting of GetOption, which
461 tries user config before default config.
Steven M. Gavac628a062002-01-19 10:33:21 +0000462 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400463 keysName = extensionName+'_cfgBindings'
464 extKeys = {}
Steven M. Gavac628a062002-01-19 10:33:21 +0000465 if self.defaultCfg['extensions'].has_section(keysName):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400466 eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000467 for eventName in eventNames:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400468 binding = self.GetOption(
469 'extensions', keysName, eventName, default='').split()
470 event = '<<' + eventName + '>>'
471 extKeys[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000472 return extKeys
473
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400474 def GetExtensionBindings(self, extensionName):
475 """Return dict {extensionName event : active or defined keybinding}.
476
477 Augment self.GetExtensionKeys(extensionName) with mapping of non-
478 configurable events (from default config) to GetOption splits,
479 as in self.__GetRawExtensionKeys.
Steven M. Gavac628a062002-01-19 10:33:21 +0000480 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400481 bindsName = extensionName + '_bindings'
482 extBinds = self.GetExtensionKeys(extensionName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000483 #add the non-configurable bindings
484 if self.defaultCfg['extensions'].has_section(bindsName):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400485 eventNames = self.defaultCfg['extensions'].GetOptionList(bindsName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000486 for eventName in eventNames:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400487 binding = self.GetOption(
488 'extensions', bindsName, eventName, default='').split()
489 event = '<<' + eventName + '>>'
490 extBinds[event] = binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000491
492 return extBinds
493
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000494 def GetKeyBinding(self, keySetName, eventStr):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400495 """Return the keybinding list for keySetName eventStr.
496
497 keySetName - name of key binding set (config-keys section).
498 eventStr - virtual event, including brackets, as in '<<event>>'.
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000499 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400500 eventName = eventStr[2:-2] #trim off the angle brackets
501 binding = self.GetOption('keys', keySetName, eventName, default='').split()
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000502 return binding
503
Steven M. Gavac628a062002-01-19 10:33:21 +0000504 def GetCurrentKeySet(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400505 "Return CurrentKeys with 'darwin' modifications."
Ronald Oussoren19302d92006-06-11 14:33:36 +0000506 result = self.GetKeySet(self.CurrentKeys())
507
Ned Deily57847df2014-03-27 20:47:04 -0700508 if sys.platform == "darwin":
509 # OS X Tk variants do not support the "Alt" keyboard modifier.
510 # So replace all keybingings that use "Alt" with ones that
511 # use the "Option" keyboard modifier.
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400512 # TODO (Ned?): the "Option" modifier does not work properly for
Ned Deily57847df2014-03-27 20:47:04 -0700513 # Cocoa Tk and XQuartz Tk so we should not use it
514 # in default OS X KeySets.
Ronald Oussoren19302d92006-06-11 14:33:36 +0000515 for k, v in result.items():
516 v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
517 if v != v2:
518 result[k] = v2
519
520 return result
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000521
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400522 def GetKeySet(self, keySetName):
523 """Return event-key dict for keySetName core plus active extensions.
524
525 If a binding defined in an extension is already in use, the
526 extension binding is disabled by being set to ''
Steven M. Gava2a63a072001-10-26 06:50:54 +0000527 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400528 keySet = self.GetCoreKeys(keySetName)
529 activeExtns = self.GetExtensions(active_only=1)
Steven M. Gavac628a062002-01-19 10:33:21 +0000530 for extn in activeExtns:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400531 extKeys = self.__GetRawExtensionKeys(extn)
Steven M. Gavac628a062002-01-19 10:33:21 +0000532 if extKeys: #the extension defines keybindings
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400533 for event in extKeys:
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000534 if extKeys[event] in keySet.values():
Steven M. Gavac628a062002-01-19 10:33:21 +0000535 #the binding is already in use
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400536 extKeys[event] = '' #disable this binding
537 keySet[event] = extKeys[event] #add binding
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000538 return keySet
539
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400540 def IsCoreBinding(self, virtualEvent):
541 """Return True if the virtual event is one of the core idle key events.
542
543 virtualEvent - string, name of the virtual event to test for,
544 without the enclosing '<< >>'
Steven M. Gavaa498af22002-02-01 01:33:36 +0000545 """
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400546 return ('<<'+virtualEvent+'>>') in self.GetCoreKeys()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000547
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400548# TODO make keyBindins a file or class attribute used for test above
549# and copied in function below
550
Steven M. Gavac628a062002-01-19 10:33:21 +0000551 def GetCoreKeys(self, keySetName=None):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400552 """Return dict of core virtual-key keybindings for keySetName.
553
554 The default keySetName None corresponds to the keyBindings base
555 dict. If keySetName is not None, bindings from the config
556 file(s) are loaded _over_ these defaults, so if there is a
557 problem getting any core binding there will be an 'ultimate last
558 resort fallback' to the CUA-ish bindings defined here.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000559 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000560 keyBindings={
Steven M. Gavaa498af22002-02-01 01:33:36 +0000561 '<<copy>>': ['<Control-c>', '<Control-C>'],
562 '<<cut>>': ['<Control-x>', '<Control-X>'],
563 '<<paste>>': ['<Control-v>', '<Control-V>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000564 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
565 '<<center-insert>>': ['<Control-l>'],
566 '<<close-all-windows>>': ['<Control-q>'],
567 '<<close-window>>': ['<Alt-F4>'],
Kurt B. Kaiser84f48032002-09-26 22:13:22 +0000568 '<<do-nothing>>': ['<Control-x>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000569 '<<end-of-file>>': ['<Control-d>'],
570 '<<python-docs>>': ['<F1>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000571 '<<python-context-help>>': ['<Shift-F1>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000572 '<<history-next>>': ['<Alt-n>'],
573 '<<history-previous>>': ['<Alt-p>'],
574 '<<interrupt-execution>>': ['<Control-c>'],
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000575 '<<view-restart>>': ['<F6>'],
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000576 '<<restart-shell>>': ['<Control-F6>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000577 '<<open-class-browser>>': ['<Alt-c>'],
578 '<<open-module>>': ['<Alt-m>'],
579 '<<open-new-window>>': ['<Control-n>'],
580 '<<open-window-from-file>>': ['<Control-o>'],
581 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000582 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000583 '<<redo>>': ['<Control-y>'],
584 '<<remove-selection>>': ['<Escape>'],
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +0000585 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000586 '<<save-window-as-file>>': ['<Alt-s>'],
587 '<<save-window>>': ['<Control-s>'],
588 '<<select-all>>': ['<Alt-a>'],
589 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000590 '<<undo>>': ['<Control-z>'],
591 '<<find-again>>': ['<Control-g>', '<F3>'],
592 '<<find-in-files>>': ['<Alt-F3>'],
593 '<<find-selection>>': ['<Control-F3>'],
594 '<<find>>': ['<Control-f>'],
595 '<<replace>>': ['<Control-h>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000596 '<<goto-line>>': ['<Alt-g>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000597 '<<smart-backspace>>': ['<Key-BackSpace>'],
Andrew Svetlovc37db102012-03-29 19:54:58 +0300598 '<<newline-and-indent>>': ['<Key-Return>', '<Key-KP_Enter>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000599 '<<smart-indent>>': ['<Key-Tab>'],
600 '<<indent-region>>': ['<Control-Key-bracketright>'],
601 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
602 '<<comment-region>>': ['<Alt-Key-3>'],
603 '<<uncomment-region>>': ['<Alt-Key-4>'],
604 '<<tabify-region>>': ['<Alt-Key-5>'],
605 '<<untabify-region>>': ['<Alt-Key-6>'],
606 '<<toggle-tabs>>': ['<Alt-Key-t>'],
Kurt B. Kaiser3069dbb2005-01-28 00:16:16 +0000607 '<<change-indentwidth>>': ['<Alt-Key-u>'],
608 '<<del-word-left>>': ['<Control-Key-BackSpace>'],
609 '<<del-word-right>>': ['<Control-Key-Delete>']
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000610 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000611 if keySetName:
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400612 for event in keyBindings:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400613 binding = self.GetKeyBinding(keySetName, event)
Steven M. Gava49745752002-02-18 01:43:11 +0000614 if binding:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400615 keyBindings[event] = binding
Steven M. Gava49745752002-02-18 01:43:11 +0000616 else: #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000617 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
618 ' -\n problem retrieving key binding for event %r'
619 '\n from key set %r.\n'
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400620 ' returning default value: %r' %
Walter Dörwald70a6b492004-02-12 17:35:32 +0000621 (event, keySetName, keyBindings[event]))
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000622 try:
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400623 print(warning, file=sys.stderr)
Amaury Forgeot d'Arcdd8d8242008-04-21 22:35:30 +0000624 except IOError:
625 pass
Steven M. Gava17d01542001-12-03 00:37:28 +0000626 return keyBindings
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000627
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400628 def GetExtraHelpSourceList(self, configSet):
629 """Return list of extra help sources from a given configSet.
Kurt B. Kaisere66675b2003-01-27 02:36:18 +0000630
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000631 Valid configSets are 'user' or 'default'. Return a list of tuples of
632 the form (menu_item , path_to_help_file , option), or return the empty
633 list. 'option' is the sequence number of the help resource. 'option'
634 values determine the position of the menu items on the Help menu,
635 therefore the returned list must be sorted by 'option'.
636
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000637 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400638 helpSources = []
639 if configSet == 'user':
640 cfgParser = self.userCfg['main']
641 elif configSet == 'default':
642 cfgParser = self.defaultCfg['main']
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000643 else:
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400644 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000645 options=cfgParser.GetOptionList('HelpFiles')
646 for option in options:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400647 value=cfgParser.Get('HelpFiles', option, default=';')
648 if value.find(';') == -1: #malformed config entry with no ';'
649 menuItem = '' #make these empty
650 helpPath = '' #so value won't be added to list
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000651 else: #config entry contains ';' as expected
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400652 value=value.split(';')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000653 menuItem=value[0].strip()
654 helpPath=value[1].strip()
655 if menuItem and helpPath: #neither are empty strings
656 helpSources.append( (menuItem,helpPath,option) )
Florent Xiclunaa7f242f2010-04-02 08:15:26 +0000657 helpSources.sort(key=lambda x: int(x[2]))
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000658 return helpSources
659
660 def GetAllExtraHelpSourcesList(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400661 """Return a list of the details of all additional help sources.
662
663 Tuples in the list are those of GetExtraHelpSourceList.
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000664 """
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400665 allHelpSources = (self.GetExtraHelpSourceList('default') +
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000666 self.GetExtraHelpSourceList('user') )
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000667 return allHelpSources
668
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000669 def LoadCfgFiles(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400670 "Load all configuration files."
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400671 for key in self.defaultCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000672 self.defaultCfg[key].Load()
673 self.userCfg[key].Load() #same keys
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000674
675 def SaveUserCfgFiles(self):
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400676 "Write all loaded user configuration files to disk."
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400677 for key in self.userCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000678 self.userCfg[key].Save()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000679
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000680
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400681idleConf = IdleConf()
682
683# TODO Revise test output, write expanded unittest
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000684### module test
685if __name__ == '__main__':
686 def dumpCfg(cfg):
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400687 print('\n', cfg, '\n')
Terry Jan Reedyf8b7e782014-10-06 01:32:21 -0400688 for key in cfg:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400689 sections = cfg[key].sections()
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400690 print(key)
691 print(sections)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000692 for section in sections:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400693 options = cfg[key].options(section)
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400694 print(section)
695 print(options)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000696 for option in options:
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400697 print(option, '=', cfg[key].Get(section, option))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000698 dumpCfg(idleConf.defaultCfg)
699 dumpCfg(idleConf.userCfg)
Terry Jan Reedy163d7fb2014-10-06 23:26:17 -0400700 print(idleConf.userCfg['main'].Get('Theme', 'name'))
Terry Jan Reedybee003c2014-09-19 22:37:24 -0400701 #print(idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal'))