blob: 694438885b5cc7eb3d08195255e0ba9799cb2f78 [file] [log] [blame]
Steven M. Gava2a63a072001-10-26 06:50:54 +00001"""
Steven M. Gavaad4f5322002-01-03 12:05:17 +00002Provides access to stored idle configuration information.
Steven M. Gavaad4f5322002-01-03 12:05:17 +00003"""
Steven M. Gavac5976402002-01-04 03:06:08 +00004# Throughout this module there is an emphasis on returning useable defaults
5# when a problem occurs in returning a requested configuration value back to
6# idle. This is to allow idle to continue to function in spite of errors in
7# the retrieval of config information. When a default is returned instead of
8# a requested config value, a message is printed to stderr to aid in
9# configuration problem notification and resolution.
10
Steven M. Gava085eb1b2002-02-05 04:52:32 +000011import os, sys, string
Steven M. Gavac11ccf32001-09-24 09:43:17 +000012from ConfigParser import ConfigParser, NoOptionError, NoSectionError
13
Neal Norwitz5b0b00f2002-11-30 19:10:19 +000014class InvalidConfigType(Exception): pass
15class InvalidConfigSet(Exception): pass
16class InvalidFgBg(Exception): pass
17class InvalidTheme(Exception): pass
18
Steven M. Gavac11ccf32001-09-24 09:43:17 +000019class IdleConfParser(ConfigParser):
20 """
21 A ConfigParser specialised for idle configuration file handling
22 """
23 def __init__(self, cfgFile, cfgDefaults=None):
24 """
25 cfgFile - string, fully specified configuration file name
26 """
27 self.file=cfgFile
28 ConfigParser.__init__(self,defaults=cfgDefaults)
29
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000030 def Get(self, section, option, type=None, default=None):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000031 """
32 Get an option value for given section/option or return default.
33 If type is specified, return as type.
34 """
Steven M. Gava41a85322001-10-29 08:05:34 +000035 if type=='bool':
36 getVal=self.getboolean
37 elif type=='int':
38 getVal=self.getint
39 else:
40 getVal=self.get
Steven M. Gavac11ccf32001-09-24 09:43:17 +000041 if self.has_option(section,option):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000042 #return getVal(section, option, raw, vars, default)
Steven M. Gava429a86a2001-10-23 10:42:12 +000043 return getVal(section, option)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000044 else:
45 return default
Steven M. Gavac11ccf32001-09-24 09:43:17 +000046
Steven M. Gavac11ccf32001-09-24 09:43:17 +000047 def GetOptionList(self,section):
48 """
49 Get an option list for given section
50 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +000051 if self.has_section(section):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000052 return self.options(section)
53 else: #return a default value
54 return []
55
Steven M. Gavac11ccf32001-09-24 09:43:17 +000056 def Load(self):
57 """
58 Load the configuration file from disk
59 """
60 self.read(self.file)
61
62class IdleUserConfParser(IdleConfParser):
63 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000064 IdleConfigParser specialised for user configuration handling.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000065 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000066
67 def AddSection(self,section):
68 """
69 if section doesn't exist, add it
70 """
71 if not self.has_section(section):
72 self.add_section(section)
73
74 def RemoveEmptySections(self):
75 """
76 remove any sections that have no options
77 """
78 for section in self.sections():
79 if not self.GetOptionList(section):
80 self.remove_section(section)
81
82 def IsEmpty(self):
83 """
84 Remove empty sections and then return 1 if parser has no sections
85 left, else return 0.
86 """
87 self.RemoveEmptySections()
88 if self.sections():
89 return 0
90 else:
91 return 1
92
93 def RemoveOption(self,section,option):
94 """
95 If section/option exists, remove it.
96 Returns 1 if option was removed, 0 otherwise.
97 """
98 if self.has_section(section):
99 return self.remove_option(section,option)
100
101 def SetOption(self,section,option,value):
102 """
103 Sets option to value, adding section if required.
104 Returns 1 if option was added or changed, otherwise 0.
105 """
106 if self.has_option(section,option):
107 if self.get(section,option)==value:
108 return 0
109 else:
110 self.set(section,option,value)
111 return 1
112 else:
113 if not self.has_section(section):
114 self.add_section(section)
115 self.set(section,option,value)
116 return 1
117
Steven M. Gavab77d3432002-03-02 07:16:21 +0000118 def RemoveFile(self):
119 """
120 Removes the user config file from disk if it exists.
121 """
122 if os.path.exists(self.file):
123 os.remove(self.file)
124
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000125 def Save(self):
126 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000127 If config isn't empty, write file to disk. If config is empty,
128 remove the file from disk if it exists.
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000129 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000130 if not self.IsEmpty():
131 cfgFile=open(self.file,'w')
132 self.write(cfgFile)
133 else:
Steven M. Gavab77d3432002-03-02 07:16:21 +0000134 self.RemoveFile()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000135
136class IdleConf:
137 """
138 holds config parsers for all idle config files:
139 default config files
140 (idle install dir)/config-main.def
141 (idle install dir)/config-extensions.def
142 (idle install dir)/config-highlight.def
143 (idle install dir)/config-keys.def
144 user config files
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000145 (user home dir)/.idlerc/config-main.cfg
146 (user home dir)/.idlerc/config-extensions.cfg
147 (user home dir)/.idlerc/config-highlight.cfg
148 (user home dir)/.idlerc/config-keys.cfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000149 """
150 def __init__(self):
151 self.defaultCfg={}
152 self.userCfg={}
153 self.cfg={}
154 self.CreateConfigHandlers()
155 self.LoadCfgFiles()
156 #self.LoadCfg()
157
158 def CreateConfigHandlers(self):
159 """
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000160 set up a dictionary of config parsers for default and user
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000161 configurations respectively
162 """
163 #build idle install path
164 if __name__ != '__main__': # we were imported
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000165 idleDir=os.path.dirname(__file__)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000166 else: # we were exec'ed (for testing only)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000167 idleDir=os.path.abspath(sys.path[0])
168 userDir=self.GetUserCfgDir()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000169 configTypes=('main','extensions','highlight','keys')
170 defCfgFiles={}
171 usrCfgFiles={}
172 for cfgType in configTypes: #build config file names
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000173 defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
174 usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000175 for cfgType in configTypes: #create config parsers
176 self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
177 self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
178
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000179 def GetUserCfgDir(self):
180 """
181 Creates (if required) and returns a filesystem directory for storing
182 user config files.
183 """
184 cfgDir='.idlerc'
185 userDir=os.path.expanduser('~')
186 if userDir != '~': #'HOME' exists as a key in os.environ
187 if not os.path.exists(userDir):
188 warn=('\n Warning: HOME environment variable points to\n '+
189 userDir+'\n but the path does not exist.\n')
190 sys.stderr.write(warn)
191 userDir='~'
192 if userDir=='~': #we still don't have a home directory
193 #traditionally idle has defaulted to os.getcwd(), is this adeqate?
194 userDir = os.getcwd() #hack for no real homedir
195 userDir=os.path.join(userDir,cfgDir)
196 if not os.path.exists(userDir):
197 try: #make the config dir if it doesn't exist yet
198 os.mkdir(userDir)
199 except IOError:
200 warn=('\n Warning: unable to create user config directory\n '+
201 userDir+'\n')
202 sys.stderr.write(warn)
203 return userDir
204
Steven M. Gava2a63a072001-10-26 06:50:54 +0000205 def GetOption(self, configType, section, option, default=None, type=None):
Steven M. Gava429a86a2001-10-23 10:42:12 +0000206 """
207 Get an option value for given config type and given general
208 configuration section/option or return a default. If type is specified,
209 return as type. Firstly the user configuration is checked, with a
210 fallback to the default configuration, and a final 'catch all'
211 fallback to a useable passed-in default if the option isn't present in
212 either the user or the default configuration.
213 configType must be one of ('main','extensions','highlight','keys')
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000214 If a default is returned a warning is printed to stderr.
Steven M. Gava429a86a2001-10-23 10:42:12 +0000215 """
216 if self.userCfg[configType].has_option(section,option):
217 return self.userCfg[configType].Get(section, option, type=type)
218 elif self.defaultCfg[configType].has_option(section,option):
219 return self.defaultCfg[configType].Get(section, option, type=type)
Steven M. Gava052937f2002-02-11 02:20:53 +0000220 else: #returning default, print warning
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000221 warning=('\n Warning: configHandler.py - IdleConf.GetOption -\n'+
222 ' problem retrieving configration option '+`option`+'\n'+
223 ' from section '+`section`+'.\n'+
224 ' returning default value: '+`default`+'\n')
225 sys.stderr.write(warning)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000226 return default
227
Steven M. Gava2a63a072001-10-26 06:50:54 +0000228 def GetSectionList(self, configSet, configType):
229 """
230 Get a list of sections from either the user or default config for
231 the given config type.
232 configSet must be either 'user' or 'default'
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000233 configType must be one of ('main','extensions','highlight','keys')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000234 """
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000235 if not (configType in ('main','extensions','highlight','keys')):
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000236 raise InvalidConfigType, 'Invalid configType specified'
Steven M. Gava2a63a072001-10-26 06:50:54 +0000237 if configSet == 'user':
238 cfgParser=self.userCfg[configType]
239 elif configSet == 'default':
240 cfgParser=self.defaultCfg[configType]
241 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000242 raise InvalidConfigSet, 'Invalid configSet specified'
Steven M. Gava2a63a072001-10-26 06:50:54 +0000243 return cfgParser.sections()
244
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000245 def GetHighlight(self, theme, element, fgBg=None):
246 """
247 return individual highlighting theme elements.
248 fgBg - string ('fg'or'bg') or None, if None return a dictionary
249 containing fg and bg colours (appropriate for passing to Tkinter in,
250 e.g., a tag_config call), otherwise fg or bg colour only as specified.
251 """
Steven M. Gava9f25e672002-02-11 02:51:18 +0000252 if self.defaultCfg['highlight'].has_section(theme):
253 themeDict=self.GetThemeDict('default',theme)
254 else:
255 themeDict=self.GetThemeDict('user',theme)
256 fore=themeDict[element+'-foreground']
257 if element=='cursor': #there is no config value for cursor bg
258 back=themeDict['normal-background']
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000259 else:
Steven M. Gava9f25e672002-02-11 02:51:18 +0000260 back=themeDict[element+'-background']
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000261 highlight={"foreground": fore,"background": back}
262 if not fgBg: #return dict of both colours
263 return highlight
264 else: #return specified colour only
265 if fgBg == 'fg':
266 return highlight["foreground"]
267 if fgBg == 'bg':
268 return highlight["background"]
269 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000270 raise InvalidFgBg, 'Invalid fgBg specified'
Steven M. Gava9f25e672002-02-11 02:51:18 +0000271
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000272 def GetThemeDict(self,type,themeName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000273 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000274 type - string, 'default' or 'user' theme type
275 themeName - string, theme name
276 Returns a dictionary which holds {option:value} for each element
277 in the specified theme. Values are loaded over a set of ultimate last
278 fallback defaults to guarantee that all theme elements are present in
279 a newly created theme.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000280 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000281 if type == 'user':
282 cfgParser=self.userCfg['highlight']
283 elif type == 'default':
284 cfgParser=self.defaultCfg['highlight']
285 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000286 raise InvalidTheme, 'Invalid theme type specified'
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000287 #foreground and background values are provded for each theme element
288 #(apart from cursor) even though all these values are not yet used
289 #by idle, to allow for their use in the future. Default values are
290 #generally black and white.
291 theme={ 'normal-foreground':'#000000',
292 'normal-background':'#ffffff',
293 'keyword-foreground':'#000000',
294 'keyword-background':'#ffffff',
295 'comment-foreground':'#000000',
296 'comment-background':'#ffffff',
297 'string-foreground':'#000000',
298 'string-background':'#ffffff',
299 'definition-foreground':'#000000',
300 'definition-background':'#ffffff',
301 'hilite-foreground':'#000000',
302 'hilite-background':'gray',
303 'break-foreground':'#ffffff',
304 'break-background':'#000000',
305 'hit-foreground':'#ffffff',
306 'hit-background':'#000000',
307 'error-foreground':'#ffffff',
308 'error-background':'#000000',
309 #cursor (only foreground can be set)
310 'cursor-foreground':'#000000',
311 #shell window
312 'stdout-foreground':'#000000',
313 'stdout-background':'#ffffff',
314 'stderr-foreground':'#000000',
315 'stderr-background':'#ffffff',
316 'console-foreground':'#000000',
317 'console-background':'#ffffff' }
318 for element in theme.keys():
Steven M. Gava052937f2002-02-11 02:20:53 +0000319 if not cfgParser.has_option(themeName,element):
320 #we are going to return a default, print warning
321 warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'+
322 ' -\n problem retrieving theme element '+`element`+
323 '\n from theme '+`themeName`+'.\n'+
324 ' returning default value: '+`theme[element]`+'\n')
325 sys.stderr.write(warning)
326 colour=cfgParser.Get(themeName,element,default=theme[element])
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000327 theme[element]=colour
328 return theme
329
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000330 def CurrentTheme(self):
331 """
332 Returns the name of the currently active theme
333 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000334 return self.GetOption('main','Theme','name',default='')
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000335
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000336 def CurrentKeys(self):
337 """
Steven M. Gava052937f2002-02-11 02:20:53 +0000338 Returns the name of the currently active key set
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000339 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000340 return self.GetOption('main','Keys','name',default='')
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000341
342 def GetExtensions(self, activeOnly=1):
343 """
344 Gets a list of all idle extensions declared in the config files.
345 activeOnly - boolean, if true only return active (enabled) extensions
346 """
Steven M. Gavac628a062002-01-19 10:33:21 +0000347 extns=self.RemoveKeyBindNames(
348 self.GetSectionList('default','extensions'))
349 userExtns=self.RemoveKeyBindNames(
350 self.GetSectionList('user','extensions'))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000351 for extn in userExtns:
352 if extn not in extns: #user has added own extension
353 extns.append(extn)
354 if activeOnly:
355 activeExtns=[]
356 for extn in extns:
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000357 if self.GetOption('extensions',extn,'enable',default=1,
358 type='bool'):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000359 #the extension is enabled
360 activeExtns.append(extn)
361 return activeExtns
362 else:
363 return extns
364
Steven M. Gavac628a062002-01-19 10:33:21 +0000365 def RemoveKeyBindNames(self,extnNameList):
366 #get rid of keybinding section names
367 names=extnNameList
368 kbNameIndicies=[]
369 for name in names:
370 if name.endswith('_bindings') or name.endswith('_cfgBindings'):
371 kbNameIndicies.append(names.index(name))
372 kbNameIndicies.sort()
373 kbNameIndicies.reverse()
374 for index in kbNameIndicies: #delete each keybinding section name
375 del(names[index])
376 return names
377
Steven M. Gavaa498af22002-02-01 01:33:36 +0000378 def GetExtnNameForEvent(self,virtualEvent):
379 """
380 Returns the name of the extension that virtualEvent is bound in, or
381 None if not bound in any extension.
382 virtualEvent - string, name of the virtual event to test for, without
383 the enclosing '<< >>'
384 """
385 extName=None
386 vEvent='<<'+virtualEvent+'>>'
387 for extn in self.GetExtensions(activeOnly=0):
388 for event in self.GetExtensionKeys(extn).keys():
389 if event == vEvent:
390 extName=extn
Steven M. Gavaa498af22002-02-01 01:33:36 +0000391 return extName
392
Steven M. Gavac628a062002-01-19 10:33:21 +0000393 def GetExtensionKeys(self,extensionName):
394 """
395 returns a dictionary of the configurable keybindings for a particular
396 extension,as they exist in the dictionary returned by GetCurrentKeySet;
Steven M. Gavaa498af22002-02-01 01:33:36 +0000397 that is, where previously used bindings are disabled.
Steven M. Gavac628a062002-01-19 10:33:21 +0000398 """
399 keysName=extensionName+'_cfgBindings'
400 activeKeys=self.GetCurrentKeySet()
401 extKeys={}
402 if self.defaultCfg['extensions'].has_section(keysName):
403 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
404 for eventName in eventNames:
405 event='<<'+eventName+'>>'
406 binding=activeKeys[event]
407 extKeys[event]=binding
408 return extKeys
409
410 def __GetRawExtensionKeys(self,extensionName):
411 """
412 returns a dictionary of the configurable keybindings for a particular
413 extension, as defined in the configuration files, or an empty dictionary
414 if no bindings are found
415 """
416 keysName=extensionName+'_cfgBindings'
417 extKeys={}
418 if self.defaultCfg['extensions'].has_section(keysName):
419 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
420 for eventName in eventNames:
421 binding=self.GetOption('extensions',keysName,
422 eventName,default='').split()
423 event='<<'+eventName+'>>'
424 extKeys[event]=binding
425 return extKeys
426
427 def GetExtensionBindings(self,extensionName):
428 """
429 Returns a dictionary of all the event bindings for a particular
430 extension. The configurable keybindings are returned as they exist in
431 the dictionary returned by GetCurrentKeySet; that is, where re-used
432 keybindings are disabled.
433 """
434 bindsName=extensionName+'_bindings'
435 extBinds=self.GetExtensionKeys(extensionName)
436 #add the non-configurable bindings
437 if self.defaultCfg['extensions'].has_section(bindsName):
438 eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
439 for eventName in eventNames:
440 binding=self.GetOption('extensions',bindsName,
441 eventName,default='').split()
442 event='<<'+eventName+'>>'
443 extBinds[event]=binding
444
445 return extBinds
446
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000447 def GetKeyBinding(self, keySetName, eventStr):
448 """
449 returns the keybinding for a specific event.
450 keySetName - string, name of key binding set
451 eventStr - string, the virtual event we want the binding for,
452 represented as a string, eg. '<<event>>'
453 """
454 eventName=eventStr[2:-2] #trim off the angle brackets
455 binding=self.GetOption('keys',keySetName,eventName,default='').split()
456 return binding
457
Steven M. Gavac628a062002-01-19 10:33:21 +0000458 def GetCurrentKeySet(self):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000459 return self.GetKeySet(self.CurrentKeys())
460
461 def GetKeySet(self,keySetName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000462 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000463 Returns a dictionary of: all requested core keybindings, plus the
Steven M. Gavac628a062002-01-19 10:33:21 +0000464 keybindings for all currently active extensions. If a binding defined
465 in an extension is already in use, that binding is disabled.
466 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000467 keySet=self.GetCoreKeys(keySetName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000468 activeExtns=self.GetExtensions(activeOnly=1)
469 for extn in activeExtns:
470 extKeys=self.__GetRawExtensionKeys(extn)
471 if extKeys: #the extension defines keybindings
472 for event in extKeys.keys():
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000473 if extKeys[event] in keySet.values():
Steven M. Gavac628a062002-01-19 10:33:21 +0000474 #the binding is already in use
475 extKeys[event]='' #disable this binding
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000476 keySet[event]=extKeys[event] #add binding
477 return keySet
478
Steven M. Gavaa498af22002-02-01 01:33:36 +0000479 def IsCoreBinding(self,virtualEvent):
480 """
481 returns true if the virtual event is bound in the core idle keybindings.
482 virtualEvent - string, name of the virtual event to test for, without
483 the enclosing '<< >>'
484 """
485 return ('<<'+virtualEvent+'>>') in self.GetCoreKeys().keys()
486
Steven M. Gavac628a062002-01-19 10:33:21 +0000487 def GetCoreKeys(self, keySetName=None):
488 """
489 returns the requested set of core keybindings, with fallbacks if
490 required.
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000491 Keybindings loaded from the config file(s) are loaded _over_ these
492 defaults, so if there is a problem getting any core binding there will
493 be an 'ultimate last resort fallback' to the CUA-ish bindings
494 defined here.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000495 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000496 keyBindings={
Steven M. Gavaa498af22002-02-01 01:33:36 +0000497 '<<copy>>': ['<Control-c>', '<Control-C>'],
498 '<<cut>>': ['<Control-x>', '<Control-X>'],
499 '<<paste>>': ['<Control-v>', '<Control-V>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000500 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
501 '<<center-insert>>': ['<Control-l>'],
502 '<<close-all-windows>>': ['<Control-q>'],
503 '<<close-window>>': ['<Alt-F4>'],
Kurt B. Kaiser84f48032002-09-26 22:13:22 +0000504 '<<do-nothing>>': ['<Control-x>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000505 '<<end-of-file>>': ['<Control-d>'],
506 '<<python-docs>>': ['<F1>'],
507 '<<python-context-help>>': ['<Shift-F1>'],
508 '<<history-next>>': ['<Alt-n>'],
509 '<<history-previous>>': ['<Alt-p>'],
510 '<<interrupt-execution>>': ['<Control-c>'],
511 '<<open-class-browser>>': ['<Alt-c>'],
512 '<<open-module>>': ['<Alt-m>'],
513 '<<open-new-window>>': ['<Control-n>'],
514 '<<open-window-from-file>>': ['<Control-o>'],
515 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000516 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000517 '<<redo>>': ['<Control-y>'],
518 '<<remove-selection>>': ['<Escape>'],
519 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
520 '<<save-window-as-file>>': ['<Alt-s>'],
521 '<<save-window>>': ['<Control-s>'],
522 '<<select-all>>': ['<Alt-a>'],
523 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000524 '<<undo>>': ['<Control-z>'],
525 '<<find-again>>': ['<Control-g>', '<F3>'],
526 '<<find-in-files>>': ['<Alt-F3>'],
527 '<<find-selection>>': ['<Control-F3>'],
528 '<<find>>': ['<Control-f>'],
529 '<<replace>>': ['<Control-h>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000530 '<<goto-line>>': ['<Alt-g>'],
531 '<<smart-backspace>>': ['<Key-BackSpace>'],
532 '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
533 '<<smart-indent>>': ['<Key-Tab>'],
534 '<<indent-region>>': ['<Control-Key-bracketright>'],
535 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
536 '<<comment-region>>': ['<Alt-Key-3>'],
537 '<<uncomment-region>>': ['<Alt-Key-4>'],
538 '<<tabify-region>>': ['<Alt-Key-5>'],
539 '<<untabify-region>>': ['<Alt-Key-6>'],
540 '<<toggle-tabs>>': ['<Alt-Key-t>'],
541 '<<change-indentwidth>>': ['<Alt-Key-u>']
542 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000543 if keySetName:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000544 for event in keyBindings.keys():
545 binding=self.GetKeyBinding(keySetName,event)
Steven M. Gava49745752002-02-18 01:43:11 +0000546 if binding:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000547 keyBindings[event]=binding
Steven M. Gava49745752002-02-18 01:43:11 +0000548 else: #we are going to return a default, print warning
549 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'+
550 ' -\n problem retrieving key binding for event '+
551 `event`+'\n from key set '+`keySetName`+'.\n'+
552 ' returning default value: '+`keyBindings[event]`+'\n')
553 sys.stderr.write(warning)
Steven M. Gava17d01542001-12-03 00:37:28 +0000554 return keyBindings
Steven M. Gava49745752002-02-18 01:43:11 +0000555
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000556 def GetExtraHelpSourceList(self,configSet):
557 """
558 Returns a list of tuples containing the details of any additional
559 help sources configured in the requested configSet ('user' or 'default')
560 , or an empty list if there are none. Returned tuples are of the form
561 form (menu_item , path_to_help_file , option).
562 """
563 helpSources=[]
564 if configSet=='user':
565 cfgParser=self.userCfg['main']
566 elif configSet=='default':
567 cfgParser=self.defaultCfg['main']
568 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000569 raise InvalidConfigSet, 'Invalid configSet specified'
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000570 options=cfgParser.GetOptionList('HelpFiles')
571 for option in options:
572 value=cfgParser.Get('HelpFiles',option,default=';')
573 if value.find(';')==-1: #malformed config entry with no ';'
574 menuItem='' #make these empty
575 helpPath='' #so value won't be added to list
576 else: #config entry contains ';' as expected
577 value=string.split(value,';')
578 menuItem=value[0].strip()
579 helpPath=value[1].strip()
580 if menuItem and helpPath: #neither are empty strings
581 helpSources.append( (menuItem,helpPath,option) )
582 return helpSources
583
584 def GetAllExtraHelpSourcesList(self):
585 """
586 Returns a list of tuples containing the details of all additional help
587 sources configured, or an empty list if there are none. Tuples are of
588 the format returned by GetExtraHelpSourceList.
589 """
590 allHelpSources=( self.GetExtraHelpSourceList('default')+
591 self.GetExtraHelpSourceList('user') )
592 return allHelpSources
593
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000594 def LoadCfgFiles(self):
595 """
596 load all configuration files.
597 """
598 for key in self.defaultCfg.keys():
599 self.defaultCfg[key].Load()
600 self.userCfg[key].Load() #same keys
601
602 def SaveUserCfgFiles(self):
603 """
604 write all loaded user configuration files back to disk
605 """
606 for key in self.userCfg.keys():
607 self.userCfg[key].Save()
608
609idleConf=IdleConf()
610
611### module test
612if __name__ == '__main__':
613 def dumpCfg(cfg):
614 print '\n',cfg,'\n'
615 for key in cfg.keys():
616 sections=cfg[key].sections()
617 print key
618 print sections
619 for section in sections:
620 options=cfg[key].options(section)
621 print section
622 print options
623 for option in options:
624 print option, '=', cfg[key].Get(section,option)
625 dumpCfg(idleConf.defaultCfg)
626 dumpCfg(idleConf.userCfg)
627 print idleConf.userCfg['main'].Get('Theme','name')
628 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')