linuxport: Merging in the fruits of my labors (Python VFS)
[xbmc:xbmc-antiquated.git] / xbmc / lib / libPython / Python / Lib / idlelib / configHandler.py
1 """Provides access to stored IDLE configuration information.
2
3 Refer to the comments at the beginning of config-main.def for a description of
4 the available configuration files and the design implemented to update user
5 configuration information.  In particular, user configuration choices which
6 duplicate the defaults will be removed from the user's configuration files,
7 and if a file becomes empty, it will be deleted.
8
9 The contents of the user files may be altered using the Options/Configure IDLE
10 menu to access the configuration GUI (configDialog.py), or manually.
11
12 Throughout this module there is an emphasis on returning useable defaults
13 when a problem occurs in returning a requested configuration value back to
14 idle. This is to allow IDLE to continue to function in spite of errors in
15 the retrieval of config information. When a default is returned instead of
16 a requested config value, a message is printed to stderr to aid in
17 configuration problem notification and resolution.
18
19 """
20 import os
21 import sys
22 import string
23 from ConfigParser import ConfigParser, NoOptionError, NoSectionError
24
25 class InvalidConfigType(Exception): pass
26 class InvalidConfigSet(Exception): pass
27 class InvalidFgBg(Exception): pass
28 class InvalidTheme(Exception): pass
29
30 class IdleConfParser(ConfigParser):
31     """
32     A ConfigParser specialised for idle configuration file handling
33     """
34     def __init__(self, cfgFile, cfgDefaults=None):
35         """
36         cfgFile - string, fully specified configuration file name
37         """
38         self.file=cfgFile
39         ConfigParser.__init__(self,defaults=cfgDefaults)
40
41     def Get(self, section, option, type=None, default=None):
42         """
43         Get an option value for given section/option or return default.
44         If type is specified, return as type.
45         """
46         if type=='bool':
47             getVal=self.getboolean
48         elif type=='int':
49             getVal=self.getint
50         else:
51             getVal=self.get
52         if self.has_option(section,option):
53             #return getVal(section, option, raw, vars, default)
54             return getVal(section, option)
55         else:
56             return default
57
58     def GetOptionList(self,section):
59         """
60         Get an option list for given section
61         """
62         if self.has_section(section):
63             return self.options(section)
64         else:  #return a default value
65             return []
66
67     def Load(self):
68         """
69         Load the configuration file from disk
70         """
71         self.read(self.file)
72
73 class IdleUserConfParser(IdleConfParser):
74     """
75     IdleConfigParser specialised for user configuration handling.
76     """
77
78     def AddSection(self,section):
79         """
80         if section doesn't exist, add it
81         """
82         if not self.has_section(section):
83             self.add_section(section)
84
85     def RemoveEmptySections(self):
86         """
87         remove any sections that have no options
88         """
89         for section in self.sections():
90             if not self.GetOptionList(section):
91                 self.remove_section(section)
92
93     def IsEmpty(self):
94         """
95         Remove empty sections and then return 1 if parser has no sections
96         left, else return 0.
97         """
98         self.RemoveEmptySections()
99         if self.sections():
100             return 0
101         else:
102             return 1
103
104     def RemoveOption(self,section,option):
105         """
106         If section/option exists, remove it.
107         Returns 1 if option was removed, 0 otherwise.
108         """
109         if self.has_section(section):
110             return self.remove_option(section,option)
111
112     def SetOption(self,section,option,value):
113         """
114         Sets option to value, adding section if required.
115         Returns 1 if option was added or changed, otherwise 0.
116         """
117         if self.has_option(section,option):
118             if self.get(section,option)==value:
119                 return 0
120             else:
121                 self.set(section,option,value)
122                 return 1
123         else:
124             if not self.has_section(section):
125                 self.add_section(section)
126             self.set(section,option,value)
127             return 1
128
129     def RemoveFile(self):
130         """
131         Removes the user config file from disk if it exists.
132         """
133         if os.path.exists(self.file):
134             os.remove(self.file)
135
136     def Save(self):
137         """Update user configuration file.
138
139         Remove empty sections. If resulting config isn't empty, write the file
140         to disk. If config is empty, remove the file from disk if it exists.
141
142         """
143         if not self.IsEmpty():
144             cfgFile=open(self.file,'w')
145             self.write(cfgFile)
146         else:
147             self.RemoveFile()
148
149 class IdleConf:
150     """
151     holds config parsers for all idle config files:
152     default config files
153         (idle install dir)/config-main.def
154         (idle install dir)/config-extensions.def
155         (idle install dir)/config-highlight.def
156         (idle install dir)/config-keys.def
157     user config  files
158         (user home dir)/.idlerc/config-main.cfg
159         (user home dir)/.idlerc/config-extensions.cfg
160         (user home dir)/.idlerc/config-highlight.cfg
161         (user home dir)/.idlerc/config-keys.cfg
162     """
163     def __init__(self):
164         self.defaultCfg={}
165         self.userCfg={}
166         self.cfg={}
167         self.CreateConfigHandlers()
168         self.LoadCfgFiles()
169         #self.LoadCfg()
170
171     def CreateConfigHandlers(self):
172         """
173         set up a dictionary of config parsers for default and user
174         configurations respectively
175         """
176         #build idle install path
177         if __name__ != '__main__': # we were imported
178             idleDir=os.path.dirname(__file__)
179         else: # we were exec'ed (for testing only)
180             idleDir=os.path.abspath(sys.path[0])
181         userDir=self.GetUserCfgDir()
182         configTypes=('main','extensions','highlight','keys')
183         defCfgFiles={}
184         usrCfgFiles={}
185         for cfgType in configTypes: #build config file names
186             defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
187             usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
188         for cfgType in configTypes: #create config parsers
189             self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
190             self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
191
192     def GetUserCfgDir(self):
193         """
194         Creates (if required) and returns a filesystem directory for storing
195         user config files.
196
197         """
198         cfgDir = '.idlerc'
199         userDir = os.path.expanduser('~')
200         if userDir != '~': # expanduser() found user home dir
201             if not os.path.exists(userDir):
202                 warn = ('\n Warning: os.path.expanduser("~") points to\n '+
203                         userDir+',\n but the path does not exist.\n')
204                 sys.stderr.write(warn)
205                 userDir = '~'
206         if userDir == "~": # still no path to home!
207             # traditionally IDLE has defaulted to os.getcwd(), is this adequate?
208             userDir = os.getcwd()
209         userDir = os.path.join(userDir, cfgDir)
210         if not os.path.exists(userDir):
211             try:
212                 os.mkdir(userDir)
213             except (OSError, IOError):
214                 warn = ('\n Warning: unable to create user config directory\n'+
215                         userDir+'\n Check path and permissions.\n Exiting!\n\n')
216                 sys.stderr.write(warn)
217                 raise SystemExit
218         return userDir
219
220     def GetOption(self, configType, section, option, default=None, type=None,
221                   warn_on_default=True):
222         """
223         Get an option value for given config type and given general
224         configuration section/option or return a default. If type is specified,
225         return as type. Firstly the user configuration is checked, with a
226         fallback to the default configuration, and a final 'catch all'
227         fallback to a useable passed-in default if the option isn't present in
228         either the user or the default configuration.
229         configType must be one of ('main','extensions','highlight','keys')
230         If a default is returned, and warn_on_default is True, a warning is
231         printed to stderr.
232
233         """
234         if self.userCfg[configType].has_option(section,option):
235             return self.userCfg[configType].Get(section, option, type=type)
236         elif self.defaultCfg[configType].has_option(section,option):
237             return self.defaultCfg[configType].Get(section, option, type=type)
238         else: #returning default, print warning
239             if warn_on_default:
240                 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
241                            ' problem retrieving configration option %r\n'
242                            ' from section %r.\n'
243                            ' returning default value: %r\n' %
244                            (option, section, default))
245                 sys.stderr.write(warning)
246             return default
247
248     def SetOption(self, configType, section, option, value):
249         """In user's config file, set section's option to value.
250
251         """
252         self.userCfg[configType].SetOption(section, option, value)
253
254     def GetSectionList(self, configSet, configType):
255         """
256         Get a list of sections from either the user or default config for
257         the given config type.
258         configSet must be either 'user' or 'default'
259         configType must be one of ('main','extensions','highlight','keys')
260         """
261         if not (configType in ('main','extensions','highlight','keys')):
262             raise InvalidConfigType, 'Invalid configType specified'
263         if configSet == 'user':
264             cfgParser=self.userCfg[configType]
265         elif configSet == 'default':
266             cfgParser=self.defaultCfg[configType]
267         else:
268             raise InvalidConfigSet, 'Invalid configSet specified'
269         return cfgParser.sections()
270
271     def GetHighlight(self, theme, element, fgBg=None):
272         """
273         return individual highlighting theme elements.
274         fgBg - string ('fg'or'bg') or None, if None return a dictionary
275         containing fg and bg colours (appropriate for passing to Tkinter in,
276         e.g., a tag_config call), otherwise fg or bg colour only as specified.
277         """
278         if self.defaultCfg['highlight'].has_section(theme):
279             themeDict=self.GetThemeDict('default',theme)
280         else:
281             themeDict=self.GetThemeDict('user',theme)
282         fore=themeDict[element+'-foreground']
283         if element=='cursor': #there is no config value for cursor bg
284             back=themeDict['normal-background']
285         else:
286             back=themeDict[element+'-background']
287         highlight={"foreground": fore,"background": back}
288         if not fgBg: #return dict of both colours
289             return highlight
290         else: #return specified colour only
291             if fgBg == 'fg':
292                 return highlight["foreground"]
293             if fgBg == 'bg':
294                 return highlight["background"]
295             else:
296                 raise InvalidFgBg, 'Invalid fgBg specified'
297
298     def GetThemeDict(self,type,themeName):
299         """
300         type - string, 'default' or 'user' theme type
301         themeName - string, theme name
302         Returns a dictionary which holds {option:value} for each element
303         in the specified theme. Values are loaded over a set of ultimate last
304         fallback defaults to guarantee that all theme elements are present in
305         a newly created theme.
306         """
307         if type == 'user':
308             cfgParser=self.userCfg['highlight']
309         elif type == 'default':
310             cfgParser=self.defaultCfg['highlight']
311         else:
312             raise InvalidTheme, 'Invalid theme type specified'
313         #foreground and background values are provded for each theme element
314         #(apart from cursor) even though all these values are not yet used
315         #by idle, to allow for their use in the future. Default values are
316         #generally black and white.
317         theme={ 'normal-foreground':'#000000',
318                 'normal-background':'#ffffff',
319                 'keyword-foreground':'#000000',
320                 'keyword-background':'#ffffff',
321                 'builtin-foreground':'#000000',
322                 'builtin-background':'#ffffff',
323                 'comment-foreground':'#000000',
324                 'comment-background':'#ffffff',
325                 'string-foreground':'#000000',
326                 'string-background':'#ffffff',
327                 'definition-foreground':'#000000',
328                 'definition-background':'#ffffff',
329                 'hilite-foreground':'#000000',
330                 'hilite-background':'gray',
331                 'break-foreground':'#ffffff',
332                 'break-background':'#000000',
333                 'hit-foreground':'#ffffff',
334                 'hit-background':'#000000',
335                 'error-foreground':'#ffffff',
336                 'error-background':'#000000',
337                 #cursor (only foreground can be set)
338                 'cursor-foreground':'#000000',
339                 #shell window
340                 'stdout-foreground':'#000000',
341                 'stdout-background':'#ffffff',
342                 'stderr-foreground':'#000000',
343                 'stderr-background':'#ffffff',
344                 'console-foreground':'#000000',
345                 'console-background':'#ffffff' }
346         for element in theme.keys():
347             if not cfgParser.has_option(themeName,element):
348                 #we are going to return a default, print warning
349                 warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'
350                            ' -\n problem retrieving theme element %r'
351                            '\n from theme %r.\n'
352                            ' returning default value: %r\n' %
353                            (element, themeName, theme[element]))
354                 sys.stderr.write(warning)
355             colour=cfgParser.Get(themeName,element,default=theme[element])
356             theme[element]=colour
357         return theme
358
359     def CurrentTheme(self):
360         """
361         Returns the name of the currently active theme
362         """
363         return self.GetOption('main','Theme','name',default='')
364
365     def CurrentKeys(self):
366         """
367         Returns the name of the currently active key set
368         """
369         return self.GetOption('main','Keys','name',default='')
370
371     def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
372         """
373         Gets a list of all idle extensions declared in the config files.
374         active_only - boolean, if true only return active (enabled) extensions
375         """
376         extns=self.RemoveKeyBindNames(
377                 self.GetSectionList('default','extensions'))
378         userExtns=self.RemoveKeyBindNames(
379                 self.GetSectionList('user','extensions'))
380         for extn in userExtns:
381             if extn not in extns: #user has added own extension
382                 extns.append(extn)
383         if active_only:
384             activeExtns=[]
385             for extn in extns:
386                 if self.GetOption('extensions', extn, 'enable', default=True,
387                                   type='bool'):
388                     #the extension is enabled
389                     if editor_only or shell_only:
390                         if editor_only:
391                             option = "enable_editor"
392                         else:
393                             option = "enable_shell"
394                         if self.GetOption('extensions', extn,option,
395                                           default=True, type='bool',
396                                           warn_on_default=False):
397                             activeExtns.append(extn)
398                     else:
399                         activeExtns.append(extn)
400             return activeExtns
401         else:
402             return extns
403
404     def RemoveKeyBindNames(self,extnNameList):
405         #get rid of keybinding section names
406         names=extnNameList
407         kbNameIndicies=[]
408         for name in names:
409             if name.endswith('_bindings') or name.endswith('_cfgBindings'):
410                 kbNameIndicies.append(names.index(name))
411         kbNameIndicies.sort()
412         kbNameIndicies.reverse()
413         for index in kbNameIndicies: #delete each keybinding section name
414             del(names[index])
415         return names
416
417     def GetExtnNameForEvent(self,virtualEvent):
418         """
419         Returns the name of the extension that virtualEvent is bound in, or
420         None if not bound in any extension.
421         virtualEvent - string, name of the virtual event to test for, without
422                        the enclosing '<< >>'
423         """
424         extName=None
425         vEvent='<<'+virtualEvent+'>>'
426         for extn in self.GetExtensions(active_only=0):
427             for event in self.GetExtensionKeys(extn).keys():
428                 if event == vEvent:
429                     extName=extn
430         return extName
431
432     def GetExtensionKeys(self,extensionName):
433         """
434         returns a dictionary of the configurable keybindings for a particular
435         extension,as they exist in the dictionary returned by GetCurrentKeySet;
436         that is, where previously used bindings are disabled.
437         """
438         keysName=extensionName+'_cfgBindings'
439         activeKeys=self.GetCurrentKeySet()
440         extKeys={}
441         if self.defaultCfg['extensions'].has_section(keysName):
442             eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
443             for eventName in eventNames:
444                 event='<<'+eventName+'>>'
445                 binding=activeKeys[event]
446                 extKeys[event]=binding
447         return extKeys
448
449     def __GetRawExtensionKeys(self,extensionName):
450         """
451         returns a dictionary of the configurable keybindings for a particular
452         extension, as defined in the configuration files, or an empty dictionary
453         if no bindings are found
454         """
455         keysName=extensionName+'_cfgBindings'
456         extKeys={}
457         if self.defaultCfg['extensions'].has_section(keysName):
458             eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
459             for eventName in eventNames:
460                 binding=self.GetOption('extensions',keysName,
461                         eventName,default='').split()
462                 event='<<'+eventName+'>>'
463                 extKeys[event]=binding
464         return extKeys
465
466     def GetExtensionBindings(self,extensionName):
467         """
468         Returns a dictionary of all the event bindings for a particular
469         extension. The configurable keybindings are returned as they exist in
470         the dictionary returned by GetCurrentKeySet; that is, where re-used
471         keybindings are disabled.
472         """
473         bindsName=extensionName+'_bindings'
474         extBinds=self.GetExtensionKeys(extensionName)
475         #add the non-configurable bindings
476         if self.defaultCfg['extensions'].has_section(bindsName):
477             eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
478             for eventName in eventNames:
479                 binding=self.GetOption('extensions',bindsName,
480                         eventName,default='').split()
481                 event='<<'+eventName+'>>'
482                 extBinds[event]=binding
483
484         return extBinds
485
486     def GetKeyBinding(self, keySetName, eventStr):
487         """
488         returns the keybinding for a specific event.
489         keySetName - string, name of key binding set
490         eventStr - string, the virtual event we want the binding for,
491                    represented as a string, eg. '<<event>>'
492         """
493         eventName=eventStr[2:-2] #trim off the angle brackets
494         binding=self.GetOption('keys',keySetName,eventName,default='').split()
495         return binding
496
497     def GetCurrentKeySet(self):
498         return self.GetKeySet(self.CurrentKeys())
499
500     def GetKeySet(self,keySetName):
501         """
502         Returns a dictionary of: all requested core keybindings, plus the
503         keybindings for all currently active extensions. If a binding defined
504         in an extension is already in use, that binding is disabled.
505         """
506         keySet=self.GetCoreKeys(keySetName)
507         activeExtns=self.GetExtensions(active_only=1)
508         for extn in activeExtns:
509             extKeys=self.__GetRawExtensionKeys(extn)
510             if extKeys: #the extension defines keybindings
511                 for event in extKeys.keys():
512                     if extKeys[event] in keySet.values():
513                         #the binding is already in use
514                         extKeys[event]='' #disable this binding
515                     keySet[event]=extKeys[event] #add binding
516         return keySet
517
518     def IsCoreBinding(self,virtualEvent):
519         """
520         returns true if the virtual event is bound in the core idle keybindings.
521         virtualEvent - string, name of the virtual event to test for, without
522                        the enclosing '<< >>'
523         """
524         return ('<<'+virtualEvent+'>>') in self.GetCoreKeys().keys()
525
526     def GetCoreKeys(self, keySetName=None):
527         """
528         returns the requested set of core keybindings, with fallbacks if
529         required.
530         Keybindings loaded from the config file(s) are loaded _over_ these
531         defaults, so if there is a problem getting any core binding there will
532         be an 'ultimate last resort fallback' to the CUA-ish bindings
533         defined here.
534         """
535         keyBindings={
536             '<<copy>>': ['<Control-c>', '<Control-C>'],
537             '<<cut>>': ['<Control-x>', '<Control-X>'],
538             '<<paste>>': ['<Control-v>', '<Control-V>'],
539             '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
540             '<<center-insert>>': ['<Control-l>'],
541             '<<close-all-windows>>': ['<Control-q>'],
542             '<<close-window>>': ['<Alt-F4>'],
543             '<<do-nothing>>': ['<Control-x>'],
544             '<<end-of-file>>': ['<Control-d>'],
545             '<<python-docs>>': ['<F1>'],
546             '<<python-context-help>>': ['<Shift-F1>'],
547             '<<history-next>>': ['<Alt-n>'],
548             '<<history-previous>>': ['<Alt-p>'],
549             '<<interrupt-execution>>': ['<Control-c>'],
550             '<<view-restart>>': ['<F6>'],
551             '<<restart-shell>>': ['<Control-F6>'],
552             '<<open-class-browser>>': ['<Alt-c>'],
553             '<<open-module>>': ['<Alt-m>'],
554             '<<open-new-window>>': ['<Control-n>'],
555             '<<open-window-from-file>>': ['<Control-o>'],
556             '<<plain-newline-and-indent>>': ['<Control-j>'],
557             '<<print-window>>': ['<Control-p>'],
558             '<<redo>>': ['<Control-y>'],
559             '<<remove-selection>>': ['<Escape>'],
560             '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
561             '<<save-window-as-file>>': ['<Alt-s>'],
562             '<<save-window>>': ['<Control-s>'],
563             '<<select-all>>': ['<Alt-a>'],
564             '<<toggle-auto-coloring>>': ['<Control-slash>'],
565             '<<undo>>': ['<Control-z>'],
566             '<<find-again>>': ['<Control-g>', '<F3>'],
567             '<<find-in-files>>': ['<Alt-F3>'],
568             '<<find-selection>>': ['<Control-F3>'],
569             '<<find>>': ['<Control-f>'],
570             '<<replace>>': ['<Control-h>'],
571             '<<goto-line>>': ['<Alt-g>'],
572             '<<smart-backspace>>': ['<Key-BackSpace>'],
573             '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
574             '<<smart-indent>>': ['<Key-Tab>'],
575             '<<indent-region>>': ['<Control-Key-bracketright>'],
576             '<<dedent-region>>': ['<Control-Key-bracketleft>'],
577             '<<comment-region>>': ['<Alt-Key-3>'],
578             '<<uncomment-region>>': ['<Alt-Key-4>'],
579             '<<tabify-region>>': ['<Alt-Key-5>'],
580             '<<untabify-region>>': ['<Alt-Key-6>'],
581             '<<toggle-tabs>>': ['<Alt-Key-t>'],
582             '<<change-indentwidth>>': ['<Alt-Key-u>']
583             }
584         if keySetName:
585             for event in keyBindings.keys():
586                 binding=self.GetKeyBinding(keySetName,event)
587                 if binding:
588                     keyBindings[event]=binding
589                 else: #we are going to return a default, print warning
590                     warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
591                                ' -\n problem retrieving key binding for event %r'
592                                '\n from key set %r.\n'
593                                ' returning default value: %r\n' %
594                                (event, keySetName, keyBindings[event]))
595                     sys.stderr.write(warning)
596         return keyBindings
597
598     def GetExtraHelpSourceList(self,configSet):
599         """Fetch list of extra help sources from a given configSet.
600
601         Valid configSets are 'user' or 'default'.  Return a list of tuples of
602         the form (menu_item , path_to_help_file , option), or return the empty
603         list.  'option' is the sequence number of the help resource.  'option'
604         values determine the position of the menu items on the Help menu,
605         therefore the returned list must be sorted by 'option'.
606
607         """
608         helpSources=[]
609         if configSet=='user':
610             cfgParser=self.userCfg['main']
611         elif configSet=='default':
612             cfgParser=self.defaultCfg['main']
613         else:
614             raise InvalidConfigSet, 'Invalid configSet specified'
615         options=cfgParser.GetOptionList('HelpFiles')
616         for option in options:
617             value=cfgParser.Get('HelpFiles',option,default=';')
618             if value.find(';')==-1: #malformed config entry with no ';'
619                 menuItem='' #make these empty
620                 helpPath='' #so value won't be added to list
621             else: #config entry contains ';' as expected
622                 value=string.split(value,';')
623                 menuItem=value[0].strip()
624                 helpPath=value[1].strip()
625             if menuItem and helpPath: #neither are empty strings
626                 helpSources.append( (menuItem,helpPath,option) )
627         helpSources.sort(self.__helpsort)
628         return helpSources
629
630     def __helpsort(self, h1, h2):
631         if int(h1[2]) < int(h2[2]):
632             return -1
633         elif int(h1[2]) > int(h2[2]):
634             return 1
635         else:
636             return 0
637
638     def GetAllExtraHelpSourcesList(self):
639         """
640         Returns a list of tuples containing the details of all additional help
641         sources configured, or an empty list if there are none. Tuples are of
642         the format returned by GetExtraHelpSourceList.
643         """
644         allHelpSources=( self.GetExtraHelpSourceList('default')+
645                 self.GetExtraHelpSourceList('user') )
646         return allHelpSources
647
648     def LoadCfgFiles(self):
649         """
650         load all configuration files.
651         """
652         for key in self.defaultCfg.keys():
653             self.defaultCfg[key].Load()
654             self.userCfg[key].Load() #same keys
655
656     def SaveUserCfgFiles(self):
657         """
658         write all loaded user configuration files back to disk
659         """
660         for key in self.userCfg.keys():
661             self.userCfg[key].Save()
662
663 idleConf=IdleConf()
664
665 ### module test
666 if __name__ == '__main__':
667     def dumpCfg(cfg):
668         print '\n',cfg,'\n'
669         for key in cfg.keys():
670             sections=cfg[key].sections()
671             print key
672             print sections
673             for section in sections:
674                 options=cfg[key].options(section)
675                 print section
676                 print options
677                 for option in options:
678                     print option, '=', cfg[key].Get(section,option)
679     dumpCfg(idleConf.defaultCfg)
680     dumpCfg(idleConf.userCfg)
681     print idleConf.userCfg['main'].Get('Theme','name')
682     #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')