blob: e0b1612c3a5fa305ca658a302c2e9e6f589edb8b [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.
18
19"""
20import os
21import sys
22import string
Steven M. Gavac11ccf32001-09-24 09:43:17 +000023from ConfigParser import ConfigParser, NoOptionError, NoSectionError
24
Neal Norwitz5b0b00f2002-11-30 19:10:19 +000025class InvalidConfigType(Exception): pass
26class InvalidConfigSet(Exception): pass
27class InvalidFgBg(Exception): pass
28class InvalidTheme(Exception): pass
29
Steven M. Gavac11ccf32001-09-24 09:43:17 +000030class 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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000040
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000041 def Get(self, section, option, type=None, default=None):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000042 """
43 Get an option value for given section/option or return default.
44 If type is specified, return as type.
45 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000046 if type=='bool':
Steven M. Gava41a85322001-10-29 08:05:34 +000047 getVal=self.getboolean
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000048 elif type=='int':
Steven M. Gava41a85322001-10-29 08:05:34 +000049 getVal=self.getint
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000050 else:
Steven M. Gava41a85322001-10-29 08:05:34 +000051 getVal=self.get
Steven M. Gavac11ccf32001-09-24 09:43:17 +000052 if self.has_option(section,option):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000053 #return getVal(section, option, raw, vars, default)
Steven M. Gava429a86a2001-10-23 10:42:12 +000054 return getVal(section, option)
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000055 else:
56 return default
Steven M. Gavac11ccf32001-09-24 09:43:17 +000057
Steven M. Gavac11ccf32001-09-24 09:43:17 +000058 def GetOptionList(self,section):
59 """
60 Get an option list for given section
61 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +000062 if self.has_section(section):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000063 return self.options(section)
64 else: #return a default value
65 return []
66
Steven M. Gavac11ccf32001-09-24 09:43:17 +000067 def Load(self):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000068 """
69 Load the configuration file from disk
Steven M. Gavac11ccf32001-09-24 09:43:17 +000070 """
71 self.read(self.file)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000072
Steven M. Gavac11ccf32001-09-24 09:43:17 +000073class IdleUserConfParser(IdleConfParser):
74 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000075 IdleConfigParser specialised for user configuration handling.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000076 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000077
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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000084
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000085 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):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000091 self.remove_section(section)
92
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000093 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000103
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000104 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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000111
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000112 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000128
Steven M. Gavab77d3432002-03-02 07:16:21 +0000129 def RemoveFile(self):
130 """
131 Removes the user config file from disk if it exists.
132 """
133 if os.path.exists(self.file):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000134 os.remove(self.file)
135
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000136 def Save(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000137 """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
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000142 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000143 if not self.IsEmpty():
144 cfgFile=open(self.file,'w')
145 self.write(cfgFile)
146 else:
Steven M. Gavab77d3432002-03-02 07:16:21 +0000147 self.RemoveFile()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000148
149class 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
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000158 (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
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000162 """
163 def __init__(self):
164 self.defaultCfg={}
165 self.userCfg={}
166 self.cfg={}
167 self.CreateConfigHandlers()
168 self.LoadCfgFiles()
169 #self.LoadCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000170
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000171 def CreateConfigHandlers(self):
172 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000173 set up a dictionary of config parsers for default and user
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000174 configurations respectively
175 """
176 #build idle install path
177 if __name__ != '__main__': # we were imported
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000178 idleDir=os.path.dirname(__file__)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000179 else: # we were exec'ed (for testing only)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000180 idleDir=os.path.abspath(sys.path[0])
181 userDir=self.GetUserCfgDir()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000182 configTypes=('main','extensions','highlight','keys')
183 defCfgFiles={}
184 usrCfgFiles={}
185 for cfgType in configTypes: #build config file names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000186 defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
187 usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000188 for cfgType in configTypes: #create config parsers
189 self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
190 self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000191
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000192 def GetUserCfgDir(self):
193 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000194 Creates (if required) and returns a filesystem directory for storing
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000195 user config files.
196 """
197 cfgDir='.idlerc'
198 userDir=os.path.expanduser('~')
199 if userDir != '~': #'HOME' exists as a key in os.environ
200 if not os.path.exists(userDir):
201 warn=('\n Warning: HOME environment variable points to\n '+
202 userDir+'\n but the path does not exist.\n')
203 sys.stderr.write(warn)
204 userDir='~'
205 if userDir=='~': #we still don't have a home directory
206 #traditionally idle has defaulted to os.getcwd(), is this adeqate?
207 userDir = os.getcwd() #hack for no real homedir
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000208 userDir=os.path.join(userDir,cfgDir)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000209 if not os.path.exists(userDir):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000210 try: #make the config dir if it doesn't exist yet
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000211 os.mkdir(userDir)
212 except IOError:
213 warn=('\n Warning: unable to create user config directory\n '+
214 userDir+'\n')
215 sys.stderr.write(warn)
216 return userDir
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000217
Steven M. Gava2a63a072001-10-26 06:50:54 +0000218 def GetOption(self, configType, section, option, default=None, type=None):
Steven M. Gava429a86a2001-10-23 10:42:12 +0000219 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000220 Get an option value for given config type and given general
Steven M. Gava429a86a2001-10-23 10:42:12 +0000221 configuration section/option or return a default. If type is specified,
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000222 return as type. Firstly the user configuration is checked, with a
223 fallback to the default configuration, and a final 'catch all'
224 fallback to a useable passed-in default if the option isn't present in
Steven M. Gava429a86a2001-10-23 10:42:12 +0000225 either the user or the default configuration.
226 configType must be one of ('main','extensions','highlight','keys')
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000227 If a default is returned a warning is printed to stderr.
Steven M. Gava429a86a2001-10-23 10:42:12 +0000228 """
229 if self.userCfg[configType].has_option(section,option):
230 return self.userCfg[configType].Get(section, option, type=type)
231 elif self.defaultCfg[configType].has_option(section,option):
232 return self.defaultCfg[configType].Get(section, option, type=type)
Steven M. Gava052937f2002-02-11 02:20:53 +0000233 else: #returning default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000234 warning=('\n Warning: configHandler.py - IdleConf.GetOption -\n'
235 ' problem retrieving configration option %r\n'
236 ' from section %r.\n'
237 ' returning default value: %r\n' %
238 (option, section, default))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000239 sys.stderr.write(warning)
Steven M. Gava429a86a2001-10-23 10:42:12 +0000240 return default
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000241
Steven M. Gava2a63a072001-10-26 06:50:54 +0000242 def GetSectionList(self, configSet, configType):
243 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000244 Get a list of sections from either the user or default config for
Steven M. Gava2a63a072001-10-26 06:50:54 +0000245 the given config type.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000246 configSet must be either 'user' or 'default'
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000247 configType must be one of ('main','extensions','highlight','keys')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000248 """
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000249 if not (configType in ('main','extensions','highlight','keys')):
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000250 raise InvalidConfigType, 'Invalid configType specified'
Steven M. Gava2a63a072001-10-26 06:50:54 +0000251 if configSet == 'user':
252 cfgParser=self.userCfg[configType]
253 elif configSet == 'default':
254 cfgParser=self.defaultCfg[configType]
255 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000256 raise InvalidConfigSet, 'Invalid configSet specified'
Steven M. Gava2a63a072001-10-26 06:50:54 +0000257 return cfgParser.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000259 def GetHighlight(self, theme, element, fgBg=None):
260 """
261 return individual highlighting theme elements.
262 fgBg - string ('fg'or'bg') or None, if None return a dictionary
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000263 containing fg and bg colours (appropriate for passing to Tkinter in,
264 e.g., a tag_config call), otherwise fg or bg colour only as specified.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000265 """
Steven M. Gava9f25e672002-02-11 02:51:18 +0000266 if self.defaultCfg['highlight'].has_section(theme):
267 themeDict=self.GetThemeDict('default',theme)
268 else:
269 themeDict=self.GetThemeDict('user',theme)
270 fore=themeDict[element+'-foreground']
271 if element=='cursor': #there is no config value for cursor bg
272 back=themeDict['normal-background']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000273 else:
Steven M. Gava9f25e672002-02-11 02:51:18 +0000274 back=themeDict[element+'-background']
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000275 highlight={"foreground": fore,"background": back}
276 if not fgBg: #return dict of both colours
277 return highlight
278 else: #return specified colour only
279 if fgBg == 'fg':
280 return highlight["foreground"]
281 if fgBg == 'bg':
282 return highlight["background"]
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000283 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000284 raise InvalidFgBg, 'Invalid fgBg specified'
Steven M. Gava9f25e672002-02-11 02:51:18 +0000285
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000286 def GetThemeDict(self,type,themeName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000287 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000288 type - string, 'default' or 'user' theme type
289 themeName - string, theme name
290 Returns a dictionary which holds {option:value} for each element
291 in the specified theme. Values are loaded over a set of ultimate last
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000292 fallback defaults to guarantee that all theme elements are present in
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000293 a newly created theme.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000294 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000295 if type == 'user':
296 cfgParser=self.userCfg['highlight']
297 elif type == 'default':
298 cfgParser=self.defaultCfg['highlight']
299 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000300 raise InvalidTheme, 'Invalid theme type specified'
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000301 #foreground and background values are provded for each theme element
302 #(apart from cursor) even though all these values are not yet used
303 #by idle, to allow for their use in the future. Default values are
304 #generally black and white.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000305 theme={ 'normal-foreground':'#000000',
306 'normal-background':'#ffffff',
307 'keyword-foreground':'#000000',
308 'keyword-background':'#ffffff',
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000309 'builtin-foreground':'#000000',
310 'builtin-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000311 'comment-foreground':'#000000',
312 'comment-background':'#ffffff',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000313 'string-foreground':'#000000',
314 'string-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000315 'definition-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000316 'definition-background':'#ffffff',
317 'hilite-foreground':'#000000',
318 'hilite-background':'gray',
319 'break-foreground':'#ffffff',
320 'break-background':'#000000',
321 'hit-foreground':'#ffffff',
322 'hit-background':'#000000',
323 'error-foreground':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000324 'error-background':'#000000',
325 #cursor (only foreground can be set)
326 'cursor-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000327 #shell window
328 'stdout-foreground':'#000000',
329 'stdout-background':'#ffffff',
330 'stderr-foreground':'#000000',
331 'stderr-background':'#ffffff',
332 'console-foreground':'#000000',
333 'console-background':'#ffffff' }
334 for element in theme.keys():
Steven M. Gava052937f2002-02-11 02:20:53 +0000335 if not cfgParser.has_option(themeName,element):
336 #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000337 warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'
338 ' -\n problem retrieving theme element %r'
339 '\n from theme %r.\n'
340 ' returning default value: %r\n' %
341 (element, themeName, theme[element]))
Steven M. Gava052937f2002-02-11 02:20:53 +0000342 sys.stderr.write(warning)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000343 colour=cfgParser.Get(themeName,element,default=theme[element])
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000344 theme[element]=colour
345 return theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000346
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000347 def CurrentTheme(self):
348 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000349 Returns the name of the currently active theme
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000350 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000351 return self.GetOption('main','Theme','name',default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000352
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000353 def CurrentKeys(self):
354 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000355 Returns the name of the currently active key set
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000356 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000357 return self.GetOption('main','Keys','name',default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000358
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000359 def GetExtensions(self, activeOnly=1):
360 """
361 Gets a list of all idle extensions declared in the config files.
362 activeOnly - boolean, if true only return active (enabled) extensions
363 """
Steven M. Gavac628a062002-01-19 10:33:21 +0000364 extns=self.RemoveKeyBindNames(
365 self.GetSectionList('default','extensions'))
366 userExtns=self.RemoveKeyBindNames(
367 self.GetSectionList('user','extensions'))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000368 for extn in userExtns:
369 if extn not in extns: #user has added own extension
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000370 extns.append(extn)
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000371 if activeOnly:
372 activeExtns=[]
373 for extn in extns:
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000374 if self.GetOption('extensions',extn,'enable',default=1,
375 type='bool'):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000376 #the extension is enabled
377 activeExtns.append(extn)
378 return activeExtns
379 else:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000380 return extns
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000381
Steven M. Gavac628a062002-01-19 10:33:21 +0000382 def RemoveKeyBindNames(self,extnNameList):
383 #get rid of keybinding section names
384 names=extnNameList
385 kbNameIndicies=[]
386 for name in names:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000387 if name.endswith('_bindings') or name.endswith('_cfgBindings'):
388 kbNameIndicies.append(names.index(name))
Steven M. Gavac628a062002-01-19 10:33:21 +0000389 kbNameIndicies.sort()
390 kbNameIndicies.reverse()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000391 for index in kbNameIndicies: #delete each keybinding section name
Steven M. Gavac628a062002-01-19 10:33:21 +0000392 del(names[index])
393 return names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000394
Steven M. Gavaa498af22002-02-01 01:33:36 +0000395 def GetExtnNameForEvent(self,virtualEvent):
396 """
397 Returns the name of the extension that virtualEvent is bound in, or
398 None if not bound in any extension.
399 virtualEvent - string, name of the virtual event to test for, without
400 the enclosing '<< >>'
401 """
402 extName=None
403 vEvent='<<'+virtualEvent+'>>'
404 for extn in self.GetExtensions(activeOnly=0):
405 for event in self.GetExtensionKeys(extn).keys():
406 if event == vEvent:
407 extName=extn
Steven M. Gavaa498af22002-02-01 01:33:36 +0000408 return extName
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000409
Steven M. Gavac628a062002-01-19 10:33:21 +0000410 def GetExtensionKeys(self,extensionName):
411 """
412 returns a dictionary of the configurable keybindings for a particular
413 extension,as they exist in the dictionary returned by GetCurrentKeySet;
Steven M. Gavaa498af22002-02-01 01:33:36 +0000414 that is, where previously used bindings are disabled.
Steven M. Gavac628a062002-01-19 10:33:21 +0000415 """
416 keysName=extensionName+'_cfgBindings'
417 activeKeys=self.GetCurrentKeySet()
418 extKeys={}
419 if self.defaultCfg['extensions'].has_section(keysName):
420 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
421 for eventName in eventNames:
422 event='<<'+eventName+'>>'
423 binding=activeKeys[event]
424 extKeys[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000425 return extKeys
426
Steven M. Gavac628a062002-01-19 10:33:21 +0000427 def __GetRawExtensionKeys(self,extensionName):
428 """
429 returns a dictionary of the configurable keybindings for a particular
430 extension, as defined in the configuration files, or an empty dictionary
431 if no bindings are found
432 """
433 keysName=extensionName+'_cfgBindings'
434 extKeys={}
435 if self.defaultCfg['extensions'].has_section(keysName):
436 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
437 for eventName in eventNames:
438 binding=self.GetOption('extensions',keysName,
439 eventName,default='').split()
440 event='<<'+eventName+'>>'
441 extKeys[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000442 return extKeys
443
Steven M. Gavac628a062002-01-19 10:33:21 +0000444 def GetExtensionBindings(self,extensionName):
445 """
446 Returns a dictionary of all the event bindings for a particular
447 extension. The configurable keybindings are returned as they exist in
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000448 the dictionary returned by GetCurrentKeySet; that is, where re-used
Steven M. Gavac628a062002-01-19 10:33:21 +0000449 keybindings are disabled.
450 """
451 bindsName=extensionName+'_bindings'
452 extBinds=self.GetExtensionKeys(extensionName)
453 #add the non-configurable bindings
454 if self.defaultCfg['extensions'].has_section(bindsName):
455 eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
456 for eventName in eventNames:
457 binding=self.GetOption('extensions',bindsName,
458 eventName,default='').split()
459 event='<<'+eventName+'>>'
460 extBinds[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000461
462 return extBinds
463
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000464 def GetKeyBinding(self, keySetName, eventStr):
465 """
466 returns the keybinding for a specific event.
467 keySetName - string, name of key binding set
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000468 eventStr - string, the virtual event we want the binding for,
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000469 represented as a string, eg. '<<event>>'
470 """
471 eventName=eventStr[2:-2] #trim off the angle brackets
472 binding=self.GetOption('keys',keySetName,eventName,default='').split()
473 return binding
474
Steven M. Gavac628a062002-01-19 10:33:21 +0000475 def GetCurrentKeySet(self):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000476 return self.GetKeySet(self.CurrentKeys())
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000477
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000478 def GetKeySet(self,keySetName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000479 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000480 Returns a dictionary of: all requested core keybindings, plus the
Steven M. Gavac628a062002-01-19 10:33:21 +0000481 keybindings for all currently active extensions. If a binding defined
482 in an extension is already in use, that binding is disabled.
483 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000484 keySet=self.GetCoreKeys(keySetName)
Steven M. Gavac628a062002-01-19 10:33:21 +0000485 activeExtns=self.GetExtensions(activeOnly=1)
486 for extn in activeExtns:
487 extKeys=self.__GetRawExtensionKeys(extn)
488 if extKeys: #the extension defines keybindings
489 for event in extKeys.keys():
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000490 if extKeys[event] in keySet.values():
Steven M. Gavac628a062002-01-19 10:33:21 +0000491 #the binding is already in use
492 extKeys[event]='' #disable this binding
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000493 keySet[event]=extKeys[event] #add binding
494 return keySet
495
Steven M. Gavaa498af22002-02-01 01:33:36 +0000496 def IsCoreBinding(self,virtualEvent):
497 """
498 returns true if the virtual event is bound in the core idle keybindings.
499 virtualEvent - string, name of the virtual event to test for, without
500 the enclosing '<< >>'
501 """
502 return ('<<'+virtualEvent+'>>') in self.GetCoreKeys().keys()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000503
Steven M. Gavac628a062002-01-19 10:33:21 +0000504 def GetCoreKeys(self, keySetName=None):
505 """
506 returns the requested set of core keybindings, with fallbacks if
507 required.
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000508 Keybindings loaded from the config file(s) are loaded _over_ these
509 defaults, so if there is a problem getting any core binding there will
510 be an 'ultimate last resort fallback' to the CUA-ish bindings
511 defined here.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000512 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000513 keyBindings={
Steven M. Gavaa498af22002-02-01 01:33:36 +0000514 '<<copy>>': ['<Control-c>', '<Control-C>'],
515 '<<cut>>': ['<Control-x>', '<Control-X>'],
516 '<<paste>>': ['<Control-v>', '<Control-V>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000517 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
518 '<<center-insert>>': ['<Control-l>'],
519 '<<close-all-windows>>': ['<Control-q>'],
520 '<<close-window>>': ['<Alt-F4>'],
Kurt B. Kaiser84f48032002-09-26 22:13:22 +0000521 '<<do-nothing>>': ['<Control-x>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000522 '<<end-of-file>>': ['<Control-d>'],
523 '<<python-docs>>': ['<F1>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000524 '<<python-context-help>>': ['<Shift-F1>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000525 '<<history-next>>': ['<Alt-n>'],
526 '<<history-previous>>': ['<Alt-p>'],
527 '<<interrupt-execution>>': ['<Control-c>'],
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000528 '<<view-restart>>': ['<F6>'],
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000529 '<<restart-shell>>': ['<Control-F6>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000530 '<<open-class-browser>>': ['<Alt-c>'],
531 '<<open-module>>': ['<Alt-m>'],
532 '<<open-new-window>>': ['<Control-n>'],
533 '<<open-window-from-file>>': ['<Control-o>'],
534 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000535 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000536 '<<redo>>': ['<Control-y>'],
537 '<<remove-selection>>': ['<Escape>'],
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +0000538 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000539 '<<save-window-as-file>>': ['<Alt-s>'],
540 '<<save-window>>': ['<Control-s>'],
541 '<<select-all>>': ['<Alt-a>'],
542 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000543 '<<undo>>': ['<Control-z>'],
544 '<<find-again>>': ['<Control-g>', '<F3>'],
545 '<<find-in-files>>': ['<Alt-F3>'],
546 '<<find-selection>>': ['<Control-F3>'],
547 '<<find>>': ['<Control-f>'],
548 '<<replace>>': ['<Control-h>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000549 '<<goto-line>>': ['<Alt-g>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000550 '<<smart-backspace>>': ['<Key-BackSpace>'],
551 '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
552 '<<smart-indent>>': ['<Key-Tab>'],
553 '<<indent-region>>': ['<Control-Key-bracketright>'],
554 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
555 '<<comment-region>>': ['<Alt-Key-3>'],
556 '<<uncomment-region>>': ['<Alt-Key-4>'],
557 '<<tabify-region>>': ['<Alt-Key-5>'],
558 '<<untabify-region>>': ['<Alt-Key-6>'],
559 '<<toggle-tabs>>': ['<Alt-Key-t>'],
560 '<<change-indentwidth>>': ['<Alt-Key-u>']
561 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000562 if keySetName:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000563 for event in keyBindings.keys():
564 binding=self.GetKeyBinding(keySetName,event)
Steven M. Gava49745752002-02-18 01:43:11 +0000565 if binding:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000566 keyBindings[event]=binding
Steven M. Gava49745752002-02-18 01:43:11 +0000567 else: #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000568 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
569 ' -\n problem retrieving key binding for event %r'
570 '\n from key set %r.\n'
571 ' returning default value: %r\n' %
572 (event, keySetName, keyBindings[event]))
Steven M. Gava49745752002-02-18 01:43:11 +0000573 sys.stderr.write(warning)
Steven M. Gava17d01542001-12-03 00:37:28 +0000574 return keyBindings
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000575
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000576 def GetExtraHelpSourceList(self,configSet):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000577 """Fetch list of extra help sources from a given configSet.
Kurt B. Kaisere66675b2003-01-27 02:36:18 +0000578
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000579 Valid configSets are 'user' or 'default'. Return a list of tuples of
580 the form (menu_item , path_to_help_file , option), or return the empty
581 list. 'option' is the sequence number of the help resource. 'option'
582 values determine the position of the menu items on the Help menu,
583 therefore the returned list must be sorted by 'option'.
584
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000585 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000586 helpSources=[]
587 if configSet=='user':
588 cfgParser=self.userCfg['main']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000589 elif configSet=='default':
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000590 cfgParser=self.defaultCfg['main']
591 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000592 raise InvalidConfigSet, 'Invalid configSet specified'
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000593 options=cfgParser.GetOptionList('HelpFiles')
594 for option in options:
595 value=cfgParser.Get('HelpFiles',option,default=';')
596 if value.find(';')==-1: #malformed config entry with no ';'
597 menuItem='' #make these empty
598 helpPath='' #so value won't be added to list
599 else: #config entry contains ';' as expected
600 value=string.split(value,';')
601 menuItem=value[0].strip()
602 helpPath=value[1].strip()
603 if menuItem and helpPath: #neither are empty strings
604 helpSources.append( (menuItem,helpPath,option) )
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000605 helpSources.sort(self.__helpsort)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000606 return helpSources
607
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000608 def __helpsort(self, h1, h2):
609 if int(h1[2]) < int(h2[2]):
610 return -1
611 elif int(h1[2]) > int(h2[2]):
612 return 1
613 else:
614 return 0
615
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000616 def GetAllExtraHelpSourcesList(self):
617 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000618 Returns a list of tuples containing the details of all additional help
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000619 sources configured, or an empty list if there are none. Tuples are of
620 the format returned by GetExtraHelpSourceList.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000621 """
622 allHelpSources=( self.GetExtraHelpSourceList('default')+
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000623 self.GetExtraHelpSourceList('user') )
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000624 return allHelpSources
625
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000626 def LoadCfgFiles(self):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000627 """
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000628 load all configuration files.
629 """
630 for key in self.defaultCfg.keys():
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000631 self.defaultCfg[key].Load()
632 self.userCfg[key].Load() #same keys
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000633
634 def SaveUserCfgFiles(self):
635 """
636 write all loaded user configuration files back to disk
637 """
638 for key in self.userCfg.keys():
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000639 self.userCfg[key].Save()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000640
641idleConf=IdleConf()
642
643### module test
644if __name__ == '__main__':
645 def dumpCfg(cfg):
646 print '\n',cfg,'\n'
647 for key in cfg.keys():
648 sections=cfg[key].sections()
649 print key
650 print sections
651 for section in sections:
652 options=cfg[key].options(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000653 print section
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000654 print options
655 for option in options:
656 print option, '=', cfg[key].Get(section,option)
657 dumpCfg(idleConf.defaultCfg)
658 dumpCfg(idleConf.userCfg)
659 print idleConf.userCfg['main'].Get('Theme','name')
660 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')