blob: b5d976900d763bb3c268d5a1948d8aafb0d81b72 [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
Guido van Rossum36e0a922007-07-20 04:05:57 +000022
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000023from idlelib import macosxSupport
24from ConfigParser import ConfigParser, NoOptionError, NoSectionError
Steven M. Gavac11ccf32001-09-24 09:43:17 +000025
Neal Norwitz5b0b00f2002-11-30 19:10:19 +000026class InvalidConfigType(Exception): pass
27class InvalidConfigSet(Exception): pass
28class InvalidFgBg(Exception): pass
29class InvalidTheme(Exception): pass
30
Steven M. Gavac11ccf32001-09-24 09:43:17 +000031class IdleConfParser(ConfigParser):
32 """
33 A ConfigParser specialised for idle configuration file handling
34 """
35 def __init__(self, cfgFile, cfgDefaults=None):
36 """
37 cfgFile - string, fully specified configuration file name
38 """
39 self.file=cfgFile
40 ConfigParser.__init__(self,defaults=cfgDefaults)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000041
Thomas Wouterscf297e42007-02-23 15:07:44 +000042 def Get(self, section, option, type=None, default=None, raw=False):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000043 """
44 Get an option value for given section/option or return default.
45 If type is specified, return as type.
46 """
Thomas Wouterscf297e42007-02-23 15:07:44 +000047 if not self.has_option(section, option):
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +000048 return default
Thomas Wouterscf297e42007-02-23 15:07:44 +000049 if type=='bool':
50 return self.getboolean(section, option)
51 elif type=='int':
52 return self.getint(section, option)
53 else:
54 return self.get(section, option, raw=raw)
Steven M. Gavac11ccf32001-09-24 09:43:17 +000055
Steven M. Gavac11ccf32001-09-24 09:43:17 +000056 def GetOptionList(self,section):
57 """
58 Get an option list for given section
59 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +000060 if self.has_section(section):
Steven M. Gavac11ccf32001-09-24 09:43:17 +000061 return self.options(section)
62 else: #return a default value
63 return []
64
Steven M. Gavac11ccf32001-09-24 09:43:17 +000065 def Load(self):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000066 """
67 Load the configuration file from disk
Steven M. Gavac11ccf32001-09-24 09:43:17 +000068 """
69 self.read(self.file)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000070
Steven M. Gavac11ccf32001-09-24 09:43:17 +000071class IdleUserConfParser(IdleConfParser):
72 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000073 IdleConfigParser specialised for user configuration handling.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000074 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000075
76 def AddSection(self,section):
77 """
78 if section doesn't exist, add it
79 """
80 if not self.has_section(section):
81 self.add_section(section)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000082
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000083 def RemoveEmptySections(self):
84 """
85 remove any sections that have no options
86 """
87 for section in self.sections():
88 if not self.GetOptionList(section):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +000089 self.remove_section(section)
90
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +000091 def IsEmpty(self):
92 """
93 Remove empty sections and then return 1 if parser has no sections
94 left, else return 0.
95 """
96 self.RemoveEmptySections()
97 if self.sections():
98 return 0
99 else:
100 return 1
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000101
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000102 def RemoveOption(self,section,option):
103 """
104 If section/option exists, remove it.
105 Returns 1 if option was removed, 0 otherwise.
106 """
107 if self.has_section(section):
108 return self.remove_option(section,option)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000109
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000110 def SetOption(self,section,option,value):
111 """
112 Sets option to value, adding section if required.
113 Returns 1 if option was added or changed, otherwise 0.
114 """
115 if self.has_option(section,option):
116 if self.get(section,option)==value:
117 return 0
118 else:
119 self.set(section,option,value)
120 return 1
121 else:
122 if not self.has_section(section):
123 self.add_section(section)
124 self.set(section,option,value)
125 return 1
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000126
Steven M. Gavab77d3432002-03-02 07:16:21 +0000127 def RemoveFile(self):
128 """
129 Removes the user config file from disk if it exists.
130 """
131 if os.path.exists(self.file):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000132 os.remove(self.file)
133
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000134 def Save(self):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000135 """Update user configuration file.
136
137 Remove empty sections. If resulting config isn't empty, write the file
138 to disk. If config is empty, remove the file from disk if it exists.
139
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000140 """
Steven M. Gava2d7bb3f2002-01-29 08:35:29 +0000141 if not self.IsEmpty():
142 cfgFile=open(self.file,'w')
143 self.write(cfgFile)
144 else:
Steven M. Gavab77d3432002-03-02 07:16:21 +0000145 self.RemoveFile()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000146
147class IdleConf:
148 """
149 holds config parsers for all idle config files:
150 default config files
151 (idle install dir)/config-main.def
152 (idle install dir)/config-extensions.def
153 (idle install dir)/config-highlight.def
154 (idle install dir)/config-keys.def
155 user config files
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000156 (user home dir)/.idlerc/config-main.cfg
157 (user home dir)/.idlerc/config-extensions.cfg
158 (user home dir)/.idlerc/config-highlight.cfg
159 (user home dir)/.idlerc/config-keys.cfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000160 """
161 def __init__(self):
162 self.defaultCfg={}
163 self.userCfg={}
164 self.cfg={}
165 self.CreateConfigHandlers()
166 self.LoadCfgFiles()
167 #self.LoadCfg()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000168
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000169 def CreateConfigHandlers(self):
170 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000171 set up a dictionary of config parsers for default and user
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000172 configurations respectively
173 """
174 #build idle install path
175 if __name__ != '__main__': # we were imported
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000176 idleDir=os.path.dirname(__file__)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000177 else: # we were exec'ed (for testing only)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000178 idleDir=os.path.abspath(sys.path[0])
179 userDir=self.GetUserCfgDir()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000180 configTypes=('main','extensions','highlight','keys')
181 defCfgFiles={}
182 usrCfgFiles={}
183 for cfgType in configTypes: #build config file names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000184 defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
185 usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000186 for cfgType in configTypes: #create config parsers
187 self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
188 self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000189
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000190 def GetUserCfgDir(self):
191 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000192 Creates (if required) and returns a filesystem directory for storing
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000193 user config files.
Tim Peters608c2ff2005-01-13 17:37:38 +0000194
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000195 """
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000196 cfgDir = '.idlerc'
197 userDir = os.path.expanduser('~')
198 if userDir != '~': # expanduser() found user home dir
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000199 if not os.path.exists(userDir):
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000200 warn = ('\n Warning: os.path.expanduser("~") points to\n '+
201 userDir+',\n but the path does not exist.\n')
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000202 sys.stderr.write(warn)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000203 userDir = '~'
204 if userDir == "~": # still no path to home!
205 # traditionally IDLE has defaulted to os.getcwd(), is this adequate?
206 userDir = os.getcwd()
207 userDir = os.path.join(userDir, cfgDir)
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000208 if not os.path.exists(userDir):
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000209 try:
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000210 os.mkdir(userDir)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000211 except (OSError, IOError):
212 warn = ('\n Warning: unable to create user config directory\n'+
213 userDir+'\n Check path and permissions.\n Exiting!\n\n')
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000214 sys.stderr.write(warn)
Kurt B. Kaiser1b6f3982005-01-11 19:29:39 +0000215 raise SystemExit
Steven M. Gava7cff66d2002-02-01 03:02:37 +0000216 return userDir
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000217
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000218 def GetOption(self, configType, section, option, default=None, type=None,
Thomas Wouterscf297e42007-02-23 15:07:44 +0000219 warn_on_default=True, raw=False):
Steven M. Gava429a86af2001-10-23 10:42:12 +0000220 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000221 Get an option value for given config type and given general
Steven M. Gava429a86af2001-10-23 10:42:12 +0000222 configuration section/option or return a default. If type is specified,
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000223 return as type. Firstly the user configuration is checked, with a
224 fallback to the default configuration, and a final 'catch all'
225 fallback to a useable passed-in default if the option isn't present in
Steven M. Gava429a86af2001-10-23 10:42:12 +0000226 either the user or the default configuration.
227 configType must be one of ('main','extensions','highlight','keys')
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000228 If a default is returned, and warn_on_default is True, a warning is
229 printed to stderr.
230
Steven M. Gava429a86af2001-10-23 10:42:12 +0000231 """
232 if self.userCfg[configType].has_option(section,option):
Thomas Wouterscf297e42007-02-23 15:07:44 +0000233 return self.userCfg[configType].Get(section, option,
234 type=type, raw=raw)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000235 elif self.defaultCfg[configType].has_option(section,option):
Thomas Wouterscf297e42007-02-23 15:07:44 +0000236 return self.defaultCfg[configType].Get(section, option,
237 type=type, raw=raw)
Steven M. Gava052937f2002-02-11 02:20:53 +0000238 else: #returning default, print warning
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000239 if warn_on_default:
240 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
241 ' problem retrieving configration option %r\n'
242 ' from section %r.\n'
243 ' returning default value: %r\n' %
244 (option, section, default))
245 sys.stderr.write(warning)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000246 return default
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000247
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000248 def SetOption(self, configType, section, option, value):
249 """In user's config file, set section's option to value.
250
251 """
252 self.userCfg[configType].SetOption(section, option, value)
253
Steven M. Gava2a63a072001-10-26 06:50:54 +0000254 def GetSectionList(self, configSet, configType):
255 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000256 Get a list of sections from either the user or default config for
Steven M. Gava2a63a072001-10-26 06:50:54 +0000257 the given config type.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000258 configSet must be either 'user' or 'default'
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000259 configType must be one of ('main','extensions','highlight','keys')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000260 """
Steven M. Gava5f28e8f2002-01-21 06:38:21 +0000261 if not (configType in ('main','extensions','highlight','keys')):
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000262 raise InvalidConfigType('Invalid configType specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000263 if configSet == 'user':
264 cfgParser=self.userCfg[configType]
265 elif configSet == 'default':
266 cfgParser=self.defaultCfg[configType]
267 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000268 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava2a63a072001-10-26 06:50:54 +0000269 return cfgParser.sections()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000270
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000271 def GetHighlight(self, theme, element, fgBg=None):
272 """
273 return individual highlighting theme elements.
274 fgBg - string ('fg'or'bg') or None, if None return a dictionary
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000275 containing fg and bg colours (appropriate for passing to Tkinter in,
276 e.g., a tag_config call), otherwise fg or bg colour only as specified.
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000277 """
Steven M. Gava9f25e672002-02-11 02:51:18 +0000278 if self.defaultCfg['highlight'].has_section(theme):
279 themeDict=self.GetThemeDict('default',theme)
280 else:
281 themeDict=self.GetThemeDict('user',theme)
282 fore=themeDict[element+'-foreground']
283 if element=='cursor': #there is no config value for cursor bg
284 back=themeDict['normal-background']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000285 else:
Steven M. Gava9f25e672002-02-11 02:51:18 +0000286 back=themeDict[element+'-background']
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000287 highlight={"foreground": fore,"background": back}
288 if not fgBg: #return dict of both colours
289 return highlight
290 else: #return specified colour only
291 if fgBg == 'fg':
292 return highlight["foreground"]
293 if fgBg == 'bg':
294 return highlight["background"]
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000295 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000296 raise InvalidFgBg('Invalid fgBg specified')
Steven M. Gava9f25e672002-02-11 02:51:18 +0000297
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000298 def GetThemeDict(self,type,themeName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000299 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000300 type - string, 'default' or 'user' theme type
301 themeName - string, theme name
302 Returns a dictionary which holds {option:value} for each element
303 in the specified theme. Values are loaded over a set of ultimate last
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000304 fallback defaults to guarantee that all theme elements are present in
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000305 a newly created theme.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000306 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000307 if type == 'user':
308 cfgParser=self.userCfg['highlight']
309 elif type == 'default':
310 cfgParser=self.defaultCfg['highlight']
311 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000312 raise InvalidTheme('Invalid theme type specified')
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000313 #foreground and background values are provded for each theme element
314 #(apart from cursor) even though all these values are not yet used
315 #by idle, to allow for their use in the future. Default values are
316 #generally black and white.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000317 theme={ 'normal-foreground':'#000000',
318 'normal-background':'#ffffff',
319 'keyword-foreground':'#000000',
320 'keyword-background':'#ffffff',
Kurt B. Kaiser73360a32004-03-08 18:15:31 +0000321 'builtin-foreground':'#000000',
322 'builtin-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000323 'comment-foreground':'#000000',
324 'comment-background':'#ffffff',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000325 'string-foreground':'#000000',
326 'string-background':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000327 'definition-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000328 'definition-background':'#ffffff',
329 'hilite-foreground':'#000000',
330 'hilite-background':'gray',
331 'break-foreground':'#ffffff',
332 'break-background':'#000000',
333 'hit-foreground':'#ffffff',
334 'hit-background':'#000000',
335 'error-foreground':'#ffffff',
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000336 'error-background':'#000000',
337 #cursor (only foreground can be set)
338 'cursor-foreground':'#000000',
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000339 #shell window
340 'stdout-foreground':'#000000',
341 'stdout-background':'#ffffff',
342 'stderr-foreground':'#000000',
343 'stderr-background':'#ffffff',
344 'console-foreground':'#000000',
345 'console-background':'#ffffff' }
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000346 for element in theme:
Steven M. Gava052937f2002-02-11 02:20:53 +0000347 if not cfgParser.has_option(themeName,element):
348 #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000349 warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'
350 ' -\n problem retrieving theme element %r'
351 '\n from theme %r.\n'
352 ' returning default value: %r\n' %
353 (element, themeName, theme[element]))
Steven M. Gava052937f2002-02-11 02:20:53 +0000354 sys.stderr.write(warning)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000355 colour=cfgParser.Get(themeName,element,default=theme[element])
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000356 theme[element]=colour
357 return theme
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000358
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000359 def CurrentTheme(self):
360 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000361 Returns the name of the currently active theme
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000362 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000363 return self.GetOption('main','Theme','name',default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000364
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000365 def CurrentKeys(self):
366 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000367 Returns the name of the currently active key set
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000368 """
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000369 return self.GetOption('main','Keys','name',default='')
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000370
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000371 def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000372 """
373 Gets a list of all idle extensions declared in the config files.
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000374 active_only - boolean, if true only return active (enabled) extensions
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000375 """
Steven M. Gavac628a062002-01-19 10:33:21 +0000376 extns=self.RemoveKeyBindNames(
377 self.GetSectionList('default','extensions'))
378 userExtns=self.RemoveKeyBindNames(
379 self.GetSectionList('user','extensions'))
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000380 for extn in userExtns:
381 if extn not in extns: #user has added own extension
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000382 extns.append(extn)
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000383 if active_only:
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000384 activeExtns=[]
385 for extn in extns:
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000386 if self.GetOption('extensions', extn, 'enable', default=True,
387 type='bool'):
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000388 #the extension is enabled
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000389 if editor_only or shell_only:
390 if editor_only:
391 option = "enable_editor"
392 else:
393 option = "enable_shell"
394 if self.GetOption('extensions', extn,option,
395 default=True, type='bool',
396 warn_on_default=False):
397 activeExtns.append(extn)
398 else:
399 activeExtns.append(extn)
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000400 return activeExtns
401 else:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000402 return extns
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000403
Steven M. Gavac628a062002-01-19 10:33:21 +0000404 def RemoveKeyBindNames(self,extnNameList):
405 #get rid of keybinding section names
406 names=extnNameList
407 kbNameIndicies=[]
408 for name in names:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000409 if name.endswith(('_bindings', '_cfgBindings')):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000410 kbNameIndicies.append(names.index(name))
Steven M. Gavac628a062002-01-19 10:33:21 +0000411 kbNameIndicies.sort()
412 kbNameIndicies.reverse()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000413 for index in kbNameIndicies: #delete each keybinding section name
Steven M. Gavac628a062002-01-19 10:33:21 +0000414 del(names[index])
415 return names
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000416
Steven M. Gavaa498af22002-02-01 01:33:36 +0000417 def GetExtnNameForEvent(self,virtualEvent):
418 """
419 Returns the name of the extension that virtualEvent is bound in, or
420 None if not bound in any extension.
421 virtualEvent - string, name of the virtual event to test for, without
422 the enclosing '<< >>'
423 """
424 extName=None
425 vEvent='<<'+virtualEvent+'>>'
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000426 for extn in self.GetExtensions(active_only=0):
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000427 for event in self.GetExtensionKeys(extn):
Steven M. Gavaa498af22002-02-01 01:33:36 +0000428 if event == vEvent:
429 extName=extn
Steven M. Gavaa498af22002-02-01 01:33:36 +0000430 return extName
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000431
Steven M. Gavac628a062002-01-19 10:33:21 +0000432 def GetExtensionKeys(self,extensionName):
433 """
434 returns a dictionary of the configurable keybindings for a particular
435 extension,as they exist in the dictionary returned by GetCurrentKeySet;
Steven M. Gavaa498af22002-02-01 01:33:36 +0000436 that is, where previously used bindings are disabled.
Steven M. Gavac628a062002-01-19 10:33:21 +0000437 """
438 keysName=extensionName+'_cfgBindings'
439 activeKeys=self.GetCurrentKeySet()
440 extKeys={}
441 if self.defaultCfg['extensions'].has_section(keysName):
442 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
443 for eventName in eventNames:
444 event='<<'+eventName+'>>'
445 binding=activeKeys[event]
446 extKeys[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000447 return extKeys
448
Steven M. Gavac628a062002-01-19 10:33:21 +0000449 def __GetRawExtensionKeys(self,extensionName):
450 """
451 returns a dictionary of the configurable keybindings for a particular
452 extension, as defined in the configuration files, or an empty dictionary
453 if no bindings are found
454 """
455 keysName=extensionName+'_cfgBindings'
456 extKeys={}
457 if self.defaultCfg['extensions'].has_section(keysName):
458 eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
459 for eventName in eventNames:
460 binding=self.GetOption('extensions',keysName,
461 eventName,default='').split()
462 event='<<'+eventName+'>>'
463 extKeys[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000464 return extKeys
465
Steven M. Gavac628a062002-01-19 10:33:21 +0000466 def GetExtensionBindings(self,extensionName):
467 """
468 Returns a dictionary of all the event bindings for a particular
469 extension. The configurable keybindings are returned as they exist in
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000470 the dictionary returned by GetCurrentKeySet; that is, where re-used
Steven M. Gavac628a062002-01-19 10:33:21 +0000471 keybindings are disabled.
472 """
473 bindsName=extensionName+'_bindings'
474 extBinds=self.GetExtensionKeys(extensionName)
475 #add the non-configurable bindings
476 if self.defaultCfg['extensions'].has_section(bindsName):
477 eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
478 for eventName in eventNames:
479 binding=self.GetOption('extensions',bindsName,
480 eventName,default='').split()
481 event='<<'+eventName+'>>'
482 extBinds[event]=binding
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000483
484 return extBinds
485
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000486 def GetKeyBinding(self, keySetName, eventStr):
487 """
488 returns the keybinding for a specific event.
489 keySetName - string, name of key binding set
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000490 eventStr - string, the virtual event we want the binding for,
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000491 represented as a string, eg. '<<event>>'
492 """
493 eventName=eventStr[2:-2] #trim off the angle brackets
494 binding=self.GetOption('keys',keySetName,eventName,default='').split()
495 return binding
496
Steven M. Gavac628a062002-01-19 10:33:21 +0000497 def GetCurrentKeySet(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000498 result = self.GetKeySet(self.CurrentKeys())
499
500 if macosxSupport.runningAsOSXApp():
501 # We're using AquaTk, replace all keybingings that use the
502 # Alt key by ones that use the Option key because the former
503 # don't work reliably.
504 for k, v in result.items():
505 v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
506 if v != v2:
507 result[k] = v2
508
509 return result
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000510
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000511 def GetKeySet(self,keySetName):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000512 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000513 Returns a dictionary of: all requested core keybindings, plus the
Steven M. Gavac628a062002-01-19 10:33:21 +0000514 keybindings for all currently active extensions. If a binding defined
515 in an extension is already in use, that binding is disabled.
516 """
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000517 keySet=self.GetCoreKeys(keySetName)
Kurt B. Kaiser4d5bc602004-06-06 01:29:22 +0000518 activeExtns=self.GetExtensions(active_only=1)
Steven M. Gavac628a062002-01-19 10:33:21 +0000519 for extn in activeExtns:
520 extKeys=self.__GetRawExtensionKeys(extn)
521 if extKeys: #the extension defines keybindings
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000522 for event in extKeys:
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000523 if extKeys[event] in keySet.values():
Steven M. Gavac628a062002-01-19 10:33:21 +0000524 #the binding is already in use
525 extKeys[event]='' #disable this binding
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000526 keySet[event]=extKeys[event] #add binding
527 return keySet
528
Steven M. Gavaa498af22002-02-01 01:33:36 +0000529 def IsCoreBinding(self,virtualEvent):
530 """
531 returns true if the virtual event is bound in the core idle keybindings.
532 virtualEvent - string, name of the virtual event to test for, without
533 the enclosing '<< >>'
534 """
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000535 return ('<<'+virtualEvent+'>>') in self.GetCoreKeys()
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000536
Steven M. Gavac628a062002-01-19 10:33:21 +0000537 def GetCoreKeys(self, keySetName=None):
538 """
539 returns the requested set of core keybindings, with fallbacks if
540 required.
Steven M. Gavaf9bb90e2002-01-24 06:02:50 +0000541 Keybindings loaded from the config file(s) are loaded _over_ these
542 defaults, so if there is a problem getting any core binding there will
543 be an 'ultimate last resort fallback' to the CUA-ish bindings
544 defined here.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000545 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000546 keyBindings={
Steven M. Gavaa498af22002-02-01 01:33:36 +0000547 '<<copy>>': ['<Control-c>', '<Control-C>'],
548 '<<cut>>': ['<Control-x>', '<Control-X>'],
549 '<<paste>>': ['<Control-v>', '<Control-V>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000550 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
551 '<<center-insert>>': ['<Control-l>'],
552 '<<close-all-windows>>': ['<Control-q>'],
553 '<<close-window>>': ['<Alt-F4>'],
Kurt B. Kaiser84f48032002-09-26 22:13:22 +0000554 '<<do-nothing>>': ['<Control-x>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000555 '<<end-of-file>>': ['<Control-d>'],
556 '<<python-docs>>': ['<F1>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000557 '<<python-context-help>>': ['<Shift-F1>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000558 '<<history-next>>': ['<Alt-n>'],
559 '<<history-previous>>': ['<Alt-p>'],
560 '<<interrupt-execution>>': ['<Control-c>'],
Kurt B. Kaiser1061e722003-01-04 01:43:53 +0000561 '<<view-restart>>': ['<F6>'],
Kurt B. Kaiser4cc5ef52003-01-22 00:23:23 +0000562 '<<restart-shell>>': ['<Control-F6>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000563 '<<open-class-browser>>': ['<Alt-c>'],
564 '<<open-module>>': ['<Alt-m>'],
565 '<<open-new-window>>': ['<Control-n>'],
566 '<<open-window-from-file>>': ['<Control-o>'],
567 '<<plain-newline-and-indent>>': ['<Control-j>'],
Steven M. Gava7981ce52002-06-11 04:45:34 +0000568 '<<print-window>>': ['<Control-p>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000569 '<<redo>>': ['<Control-y>'],
570 '<<remove-selection>>': ['<Escape>'],
Kurt B. Kaiser2303b1c2003-11-24 05:26:16 +0000571 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
Steven M. Gava17d01542001-12-03 00:37:28 +0000572 '<<save-window-as-file>>': ['<Alt-s>'],
573 '<<save-window>>': ['<Control-s>'],
574 '<<select-all>>': ['<Alt-a>'],
575 '<<toggle-auto-coloring>>': ['<Control-slash>'],
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000576 '<<undo>>': ['<Control-z>'],
577 '<<find-again>>': ['<Control-g>', '<F3>'],
578 '<<find-in-files>>': ['<Alt-F3>'],
579 '<<find-selection>>': ['<Control-F3>'],
580 '<<find>>': ['<Control-f>'],
581 '<<replace>>': ['<Control-h>'],
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000582 '<<goto-line>>': ['<Alt-g>'],
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000583 '<<smart-backspace>>': ['<Key-BackSpace>'],
584 '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
585 '<<smart-indent>>': ['<Key-Tab>'],
586 '<<indent-region>>': ['<Control-Key-bracketright>'],
587 '<<dedent-region>>': ['<Control-Key-bracketleft>'],
588 '<<comment-region>>': ['<Alt-Key-3>'],
589 '<<uncomment-region>>': ['<Alt-Key-4>'],
590 '<<tabify-region>>': ['<Alt-Key-5>'],
591 '<<untabify-region>>': ['<Alt-Key-6>'],
592 '<<toggle-tabs>>': ['<Alt-Key-t>'],
Kurt B. Kaiser3069dbb2005-01-28 00:16:16 +0000593 '<<change-indentwidth>>': ['<Alt-Key-u>'],
594 '<<del-word-left>>': ['<Control-Key-BackSpace>'],
595 '<<del-word-right>>': ['<Control-Key-Delete>']
Kurt B. Kaisera9f8cbc2002-09-14 03:17:01 +0000596 }
Steven M. Gava17d01542001-12-03 00:37:28 +0000597 if keySetName:
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000598 for event in keyBindings:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000599 binding=self.GetKeyBinding(keySetName,event)
Steven M. Gava49745752002-02-18 01:43:11 +0000600 if binding:
Steven M. Gava0cae01c2002-01-04 07:53:06 +0000601 keyBindings[event]=binding
Steven M. Gava49745752002-02-18 01:43:11 +0000602 else: #we are going to return a default, print warning
Walter Dörwald70a6b492004-02-12 17:35:32 +0000603 warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
604 ' -\n problem retrieving key binding for event %r'
605 '\n from key set %r.\n'
606 ' returning default value: %r\n' %
607 (event, keySetName, keyBindings[event]))
Steven M. Gava49745752002-02-18 01:43:11 +0000608 sys.stderr.write(warning)
Steven M. Gava17d01542001-12-03 00:37:28 +0000609 return keyBindings
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000610
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000611 def GetExtraHelpSourceList(self,configSet):
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000612 """Fetch list of extra help sources from a given configSet.
Kurt B. Kaisere66675b2003-01-27 02:36:18 +0000613
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000614 Valid configSets are 'user' or 'default'. Return a list of tuples of
615 the form (menu_item , path_to_help_file , option), or return the empty
616 list. 'option' is the sequence number of the help resource. 'option'
617 values determine the position of the menu items on the Help menu,
618 therefore the returned list must be sorted by 'option'.
619
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000620 """
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000621 helpSources=[]
622 if configSet=='user':
623 cfgParser=self.userCfg['main']
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000624 elif configSet=='default':
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000625 cfgParser=self.defaultCfg['main']
626 else:
Kurt B. Kaiserad667422007-08-23 01:06:15 +0000627 raise InvalidConfigSet('Invalid configSet specified')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000628 options=cfgParser.GetOptionList('HelpFiles')
629 for option in options:
630 value=cfgParser.Get('HelpFiles',option,default=';')
631 if value.find(';')==-1: #malformed config entry with no ';'
632 menuItem='' #make these empty
633 helpPath='' #so value won't be added to list
634 else: #config entry contains ';' as expected
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000635 value=value.split(';')
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000636 menuItem=value[0].strip()
637 helpPath=value[1].strip()
638 if menuItem and helpPath: #neither are empty strings
639 helpSources.append( (menuItem,helpPath,option) )
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000640 helpSources.sort(self.__helpsort)
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000641 return helpSources
642
Kurt B. Kaiser8e92bf72003-01-14 22:03:31 +0000643 def __helpsort(self, h1, h2):
644 if int(h1[2]) < int(h2[2]):
645 return -1
646 elif int(h1[2]) > int(h2[2]):
647 return 1
648 else:
649 return 0
650
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000651 def GetAllExtraHelpSourcesList(self):
652 """
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000653 Returns a list of tuples containing the details of all additional help
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000654 sources configured, or an empty list if there are none. Tuples are of
655 the format returned by GetExtraHelpSourceList.
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000656 """
657 allHelpSources=( self.GetExtraHelpSourceList('default')+
Steven M. Gava085eb1b2002-02-05 04:52:32 +0000658 self.GetExtraHelpSourceList('user') )
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000659 return allHelpSources
660
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000661 def LoadCfgFiles(self):
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000662 """
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000663 load all configuration files.
664 """
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000665 for key in self.defaultCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000666 self.defaultCfg[key].Load()
667 self.userCfg[key].Load() #same keys
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000668
669 def SaveUserCfgFiles(self):
670 """
671 write all loaded user configuration files back to disk
672 """
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000673 for key in self.userCfg:
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000674 self.userCfg[key].Save()
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000675
676idleConf=IdleConf()
677
678### module test
679if __name__ == '__main__':
680 def dumpCfg(cfg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000681 print('\n',cfg,'\n')
Kurt B. Kaisere0712772007-08-23 05:25:55 +0000682 for key in cfg:
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000683 sections=cfg[key].sections()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000684 print(key)
685 print(sections)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000686 for section in sections:
687 options=cfg[key].options(section)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000688 print(section)
689 print(options)
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000690 for option in options:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000691 print(option, '=', cfg[key].Get(section,option))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000692 dumpCfg(idleConf.defaultCfg)
693 dumpCfg(idleConf.userCfg)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000694 print(idleConf.userCfg['main'].Get('Theme','name'))
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000695 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')