ยปCore Development>Code coverage>Lib/idlelib/configHandler.py

Python code coverage for Lib/idlelib/configHandler.py

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