blob: cf2b6dbc82653acff9587c0be6047aff8ad77f15 [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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +00008# a requested config value, a message is printed to stderr to aid in
9# configuration problem notification and resolution.
Steven M. Gavac5976402002-01-04 03:06:08 +000010
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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000029
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 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000035 if type=='bool':
Steven M. Gava41a85322001-10-29 08:05:34 +000036 getVal=self.getboolean
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000037 elif type=='int':
Steven M. Gava41a85322001-10-29 08:05:34 +000038 getVal=self.getint
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000039 else:
Steven M. Gava41a85322001-10-29 08:05:34 +000040 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):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000057 """
58 Load the configuration file from disk
Steven M. Gavac11ccf32001-09-24 09:43:17 +000059 """
60 self.read(self.file)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000061
Steven M. Gavac11ccf32001-09-24 09:43:17 +000062class 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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000073
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000074 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):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000080 self.remove_section(section)
81
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000082 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000092
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000093 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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000100
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000101 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000117
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):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000123 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()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000157
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000158 def CreateConfigHandlers(self):
159 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +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])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000178
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000179 def GetUserCfgDir(self):
180 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000181 Creates (if required) and returns a filesystem directory for storing
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000182 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000195 userDir=os.path.join(userDir,cfgDir)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000196 if not os.path.exists(userDir):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000197 try: #make the config dir if it doesn't exist yet
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000198 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000204
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 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000207 Get an option value for given config type and given general
Steven M. Gava429a86a2001-10-23 10:42:12 +0000208 configuration section/option or return a default. If type is specified,
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000209 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
Steven M. Gava429a86a2001-10-23 10:42:12 +0000212 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000227
Steven M. Gava2a63a072001-10-26 06:50:54 +0000228 def GetSectionList(self, configSet, configType):
229 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000230 Get a list of sections from either the user or default config for
Steven M. Gava2a63a072001-10-26 06:50:54 +0000231 the given config type.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000232 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()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000244
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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000249 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.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000251 """
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']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +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"]
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000269 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000278 fallback defaults to guarantee that all theme elements are present in
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000279 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.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000291 theme={ 'normal-foreground':'#000000',
292 'normal-background':'#ffffff',
293 'keyword-foreground':'#000000',
294 'keyword-background':'#ffffff',
295 'comment-foreground':'#000000',
296 'comment-background':'#ffffff',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000297 'string-foreground':'#000000',
298 'string-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000299 'definition-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000300 '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',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000308 'error-background':'#000000',
309 #cursor (only foreground can be set)
310 'cursor-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000311 #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)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000326 colour=cfgParser.Get(themeName,element,default=theme[element])
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000327 theme[element]=colour
328 return theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000329
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000330 def CurrentTheme(self):
331 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000332 Returns the name of the currently active theme
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000333 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000334 return self.GetOption('main','Theme','name',default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000335
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000336 def CurrentKeys(self):
337 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +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='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000341
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000342 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000353 extns.append(extn)
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000354 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:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000363 return extns
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000364
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:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000370 if name.endswith('_bindings') or name.endswith('_cfgBindings'):
371 kbNameIndicies.append(names.index(name))
Steven M. Gavac628a062002-01-19 10:33:21 +0000372 kbNameIndicies.sort()
373 kbNameIndicies.reverse()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000374 for index in kbNameIndicies: #delete each keybinding section name
Steven M. Gavac628a062002-01-19 10:33:21 +0000375 del(names[index])
376 return names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000377
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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000392
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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000408 return extKeys
409
Steven M. Gavac628a062002-01-19 10:33:21 +0000410 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000425 return extKeys
426
Steven M. Gavac628a062002-01-19 10:33:21 +0000427 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000431 the dictionary returned by GetCurrentKeySet; that is, where re-used
Steven M. Gavac628a062002-01-19 10:33:21 +0000432 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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000444
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
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000451 eventStr - string, the virtual event we want the binding for,
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000452 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())
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000460
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000461 def GetKeySet(self,keySetName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000462 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +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()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000486
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>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000507 '<<python-context-help>>': ['<Shift-F1>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000508 '<<history-next>>': ['<Alt-n>'],
509 '<<history-previous>>': ['<Alt-p>'],
510 '<<interrupt-execution>>': ['<Control-c>'],
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000511 '<<view-restart>>': ['<F6>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000512 '<<open-class-browser>>': ['<Alt-c>'],
513 '<<open-module>>': ['<Alt-m>'],
514 '<<open-new-window>>': ['<Control-n>'],
515 '<<open-window-from-file>>': ['<Control-o>'],
516 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000517 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000518 '<<redo>>': ['<Control-y>'],
519 '<<remove-selection>>': ['<Escape>'],
520 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
521 '<<save-window-as-file>>': ['<Alt-s>'],
522 '<<save-window>>': ['<Control-s>'],
523 '<<select-all>>': ['<Alt-a>'],
524 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000525 '<<undo>>': ['<Control-z>'],
526 '<<find-again>>': ['<Control-g>', '<F3>'],
527 '<<find-in-files>>': ['<Alt-F3>'],
528 '<<find-selection>>': ['<Control-F3>'],
529 '<<find>>': ['<Control-f>'],
530 '<<replace>>': ['<Control-h>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000531 '<<goto-line>>': ['<Alt-g>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000532 '<<smart-backspace>>': ['<Key-BackSpace>'],
533 '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
534 '<<smart-indent>>': ['<Key-Tab>'],
535 '<<indent-region>>': ['<Control-Key-bracketright>'],
536 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
537 '<<comment-region>>': ['<Alt-Key-3>'],
538 '<<uncomment-region>>': ['<Alt-Key-4>'],
539 '<<tabify-region>>': ['<Alt-Key-5>'],
540 '<<untabify-region>>': ['<Alt-Key-6>'],
541 '<<toggle-tabs>>': ['<Alt-Key-t>'],
542 '<<change-indentwidth>>': ['<Alt-Key-u>']
543 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000544 if keySetName:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000545 for event in keyBindings.keys():
546 binding=self.GetKeyBinding(keySetName,event)
Steven M. Gava49745752002-02-18 01:43:11 +0000547 if binding:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000548 keyBindings[event]=binding
Steven M. Gava49745752002-02-18 01:43:11 +0000549 else: #we are going to return a default, print warning
550 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'+
551 ' -\n problem retrieving key binding for event '+
552 `event`+'\n from key set '+`keySetName`+'.\n'+
553 ' returning default value: '+`keyBindings[event]`+'\n')
554 sys.stderr.write(warning)
Steven M. Gava17d01542001-12-03 00:37:28 +0000555 return keyBindings
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000556
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000557 def GetExtraHelpSourceList(self,configSet):
558 """
559 Returns a list of tuples containing the details of any additional
560 help sources configured in the requested configSet ('user' or 'default')
561 , or an empty list if there are none. Returned tuples are of the form
562 form (menu_item , path_to_help_file , option).
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000563 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000564 helpSources=[]
565 if configSet=='user':
566 cfgParser=self.userCfg['main']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000567 elif configSet=='default':
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000568 cfgParser=self.defaultCfg['main']
569 else:
Neal Norwitz5b0b00f2002-11-30 19:10:19 +0000570 raise InvalidConfigSet, 'Invalid configSet specified'
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000571 options=cfgParser.GetOptionList('HelpFiles')
572 for option in options:
573 value=cfgParser.Get('HelpFiles',option,default=';')
574 if value.find(';')==-1: #malformed config entry with no ';'
575 menuItem='' #make these empty
576 helpPath='' #so value won't be added to list
577 else: #config entry contains ';' as expected
578 value=string.split(value,';')
579 menuItem=value[0].strip()
580 helpPath=value[1].strip()
581 if menuItem and helpPath: #neither are empty strings
582 helpSources.append( (menuItem,helpPath,option) )
583 return helpSources
584
585 def GetAllExtraHelpSourcesList(self):
586 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000587 Returns a list of tuples containing the details of all additional help
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000588 sources configured, or an empty list if there are none. Tuples are of
589 the format returned by GetExtraHelpSourceList.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000590 """
591 allHelpSources=( self.GetExtraHelpSourceList('default')+
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000592 self.GetExtraHelpSourceList('user') )
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000593 return allHelpSources
594
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000595 def LoadCfgFiles(self):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000596 """
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000597 load all configuration files.
598 """
599 for key in self.defaultCfg.keys():
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000600 self.defaultCfg[key].Load()
601 self.userCfg[key].Load() #same keys
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000602
603 def SaveUserCfgFiles(self):
604 """
605 write all loaded user configuration files back to disk
606 """
607 for key in self.userCfg.keys():
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000608 self.userCfg[key].Save()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000609
610idleConf=IdleConf()
611
612### module test
613if __name__ == '__main__':
614 def dumpCfg(cfg):
615 print '\n',cfg,'\n'
616 for key in cfg.keys():
617 sections=cfg[key].sections()
618 print key
619 print sections
620 for section in sections:
621 options=cfg[key].options(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000622 print section
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000623 print options
624 for option in options:
625 print option, '=', cfg[key].Get(section,option)
626 dumpCfg(idleConf.defaultCfg)
627 dumpCfg(idleConf.userCfg)
628 print idleConf.userCfg['main'].Get('Theme','name')
629 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')