blob: b84fc4eb3bd7ae88d38474120f9781953da16d1b [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. Gavac11ccf32001-09-24 09:43:17 +00003
Steven M. Gavaad4f5322002-01-03 12:05:17 +00004Throughout this module there is an emphasis on returning useable defaults if
5there is a problem returning a requested configuration value back to idle.
6This is to allow idle to continue to function in spite of errors in the
7retrieval of config information. When a default is returned instead of a
8requested config value, a message is printed to stderr to aid in
9configuration problem notification and resolution.
10"""
Steven M. Gavac11ccf32001-09-24 09:43:17 +000011import os
12import sys
13from ConfigParser import ConfigParser, NoOptionError, NoSectionError
14
15class IdleConfParser(ConfigParser):
16 """
17 A ConfigParser specialised for idle configuration file handling
18 """
19 def __init__(self, cfgFile, cfgDefaults=None):
20 """
21 cfgFile - string, fully specified configuration file name
22 """
23 self.file=cfgFile
24 ConfigParser.__init__(self,defaults=cfgDefaults)
25
Steven M. Gavaad4f5322002-01-03 12:05:17 +000026 def Get(self, section, option, type=None): #,default=None)
Steven M. Gavac11ccf32001-09-24 09:43:17 +000027 """
28 Get an option value for given section/option or return default.
29 If type is specified, return as type.
Steven M. Gavaad4f5322002-01-03 12:05:17 +000030 If a default is returned a warning is printed to stderr.
Steven M. Gavac11ccf32001-09-24 09:43:17 +000031 """
Steven M. Gava41a85322001-10-29 08:05:34 +000032 if type=='bool':
33 getVal=self.getboolean
34 elif type=='int':
35 getVal=self.getint
36 else:
37 getVal=self.get
Steven M. Gavac11ccf32001-09-24 09:43:17 +000038 if self.has_option(section,option):
Steven M. Gava429a86af2001-10-23 10:42:12 +000039 #return getVal(section, option, raw, vars)
40 return getVal(section, option)
Steven M. Gavaad4f5322002-01-03 12:05:17 +000041# #the following handled in IdleConf.GetOption instead
42# else:
43# warning=('\n Warning: configHandler.py - IdleConfParser.Get -\n'+
44# ' problem retrieving configration option '+`option`+'\n'+
45# ' from section '+`section`+'.\n'+
46# ' returning default value: '+`default`+'\n')
47# sys.stderr.write(warning)
48# return default
Steven M. Gavac11ccf32001-09-24 09:43:17 +000049
Steven M. Gavac11ccf32001-09-24 09:43:17 +000050 def GetOptionList(self,section):
51 """
52 Get an option list for given section
53 """
54 if self.has_section:
55 return self.options(section)
56 else: #return a default value
57 return []
58
Steven M. Gavac11ccf32001-09-24 09:43:17 +000059 def Load(self):
60 """
61 Load the configuration file from disk
62 """
63 self.read(self.file)
64
65class IdleUserConfParser(IdleConfParser):
66 """
67 IdleConfigParser specialised for user configuration handling
68 """
69 def Save(self):
70 """
71 write loaded user configuration file back to disk
72 """
73 # this is a user config, it can be written to disk
74 self.write()
75
76class IdleConf:
77 """
78 holds config parsers for all idle config files:
79 default config files
80 (idle install dir)/config-main.def
81 (idle install dir)/config-extensions.def
82 (idle install dir)/config-highlight.def
83 (idle install dir)/config-keys.def
84 user config files
Steven M. Gavaad4f5322002-01-03 12:05:17 +000085 (user home dir)/.idlerc/config-main.cfg
86 (user home dir)/.idlerc/config-extensions.cfg
87 (user home dir)/.idlerc/config-highlight.cfg
88 (user home dir)/.idlerc/config-keys.cfg
Steven M. Gavac11ccf32001-09-24 09:43:17 +000089 """
90 def __init__(self):
91 self.defaultCfg={}
92 self.userCfg={}
93 self.cfg={}
94 self.CreateConfigHandlers()
95 self.LoadCfgFiles()
96 #self.LoadCfg()
97
98 def CreateConfigHandlers(self):
99 """
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000100 set up a dictionary of config parsers for default and user
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000101 configurations respectively
102 """
103 #build idle install path
104 if __name__ != '__main__': # we were imported
105 idledir=os.path.dirname(__file__)
106 else: # we were exec'ed (for testing only)
107 idledir=os.path.abspath(sys.path[0])
108 #print idledir
109 try: #build user home path
110 userdir = os.environ['HOME'] #real home directory
111 except KeyError:
112 userdir = os.getcwd() #hack for os'es without real homedirs
113 userdir=os.path.join(userdir,'.idlerc')
114 #print userdir
115 if not os.path.exists(userdir):
116 os.mkdir(userdir)
117 configTypes=('main','extensions','highlight','keys')
118 defCfgFiles={}
119 usrCfgFiles={}
120 for cfgType in configTypes: #build config file names
121 defCfgFiles[cfgType]=os.path.join(idledir,'config-'+cfgType+'.def')
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000122 usrCfgFiles[cfgType]=os.path.join(userdir,'config-'+cfgType+'.cfg')
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000123 for cfgType in configTypes: #create config parsers
124 self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
125 self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
126
Steven M. Gava2a63a072001-10-26 06:50:54 +0000127 def GetOption(self, configType, section, option, default=None, type=None):
Steven M. Gava429a86af2001-10-23 10:42:12 +0000128 """
129 Get an option value for given config type and given general
130 configuration section/option or return a default. If type is specified,
131 return as type. Firstly the user configuration is checked, with a
132 fallback to the default configuration, and a final 'catch all'
133 fallback to a useable passed-in default if the option isn't present in
134 either the user or the default configuration.
135 configType must be one of ('main','extensions','highlight','keys')
136 """
137 if self.userCfg[configType].has_option(section,option):
138 return self.userCfg[configType].Get(section, option, type=type)
139 elif self.defaultCfg[configType].has_option(section,option):
140 return self.defaultCfg[configType].Get(section, option, type=type)
141 else:
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000142 warning=('\n Warning: configHandler.py - IdleConf.GetOption -\n'+
143 ' problem retrieving configration option '+`option`+'\n'+
144 ' from section '+`section`+'.\n'+
145 ' returning default value: '+`default`+'\n')
146 sys.stderr.write(warning)
Steven M. Gava429a86af2001-10-23 10:42:12 +0000147 return default
148
Steven M. Gava2a63a072001-10-26 06:50:54 +0000149 def GetSectionList(self, configSet, configType):
150 """
151 Get a list of sections from either the user or default config for
152 the given config type.
153 configSet must be either 'user' or 'default'
154 configType must be one of ('extensions','highlight','keys')
155 """
156 if not (configType in ('extensions','highlight','keys')):
157 raise 'Invalid configType specified'
158 if configSet == 'user':
159 cfgParser=self.userCfg[configType]
160 elif configSet == 'default':
161 cfgParser=self.defaultCfg[configType]
162 else:
163 raise 'Invalid configSet specified'
164
165 return cfgParser.sections()
166
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000167 def GetHighlight(self, theme, element, fgBg=None):
168 """
169 return individual highlighting theme elements.
170 fgBg - string ('fg'or'bg') or None, if None return a dictionary
171 containing fg and bg colours (appropriate for passing to Tkinter in,
172 e.g., a tag_config call), otherwise fg or bg colour only as specified.
173 """
Steven M. Gava99300612001-11-04 07:03:08 +0000174 #get some fallback defaults
175 defaultFg=self.GetOption('highlight', theme, 'normal' + "-foreground",
176 default='#000000')
177 defaultBg=self.GetOption('highlight', theme, 'normal' + "-background",
178 default='#ffffff')
179 #try for requested element colours
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000180 fore = self.GetOption('highlight', theme, element + "-foreground")
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000181 back = None
182 if element == 'cursor': #there is no config value for cursor bg
183 back = None
184 else:
185 back = self.GetOption('highlight', theme, element + "-background")
Steven M. Gava99300612001-11-04 07:03:08 +0000186 #fall back if required
187 if not fore: fore=defaultFg
188 if not back: back=defaultBg
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000189 highlight={"foreground": fore,"background": back}
190 if not fgBg: #return dict of both colours
191 return highlight
192 else: #return specified colour only
193 if fgBg == 'fg':
194 return highlight["foreground"]
195 if fgBg == 'bg':
196 return highlight["background"]
197 else:
198 raise 'Invalid fgBg specified'
199
Steven M. Gavae16d94b2001-11-03 05:07:28 +0000200
Steven M. Gava2a63a072001-10-26 06:50:54 +0000201 def GetTheme(self, name=None):
202 """
203 Gets the requested theme or returns a final fallback theme in case
204 one can't be obtained from either the user or default config files.
205 """
206 pass
207
Steven M. Gavaad4f5322002-01-03 12:05:17 +0000208 def CurrentTheme(self):
209 """
210 Returns the name of the currently active theme
211 """
212 return self.GetOption('main','Theme','name')
213
214
215 def CurrentKeys(self):
216 """
217 Returns the name of the currently active theme
218 """
219 return self.GetOption('main','Keys','name')
220
221 def GetExtensions(self, activeOnly=1):
222 """
223 Gets a list of all idle extensions declared in the config files.
224 activeOnly - boolean, if true only return active (enabled) extensions
225 """
226 extns=self.GetSectionList('default','extensions')
227 userExtns=self.GetSectionList('user','extensions')
228 for extn in userExtns:
229 if extn not in extns: #user has added own extension
230 extns.append(extn)
231 if activeOnly:
232 activeExtns=[]
233 for extn in extns:
234 if self.GetOption('extensions',extn,'enable',default=1,type='bool'):
235 #the extension is enabled
236 activeExtns.append(extn)
237 return activeExtns
238 else:
239 return extns
240
Steven M. Gava17d01542001-12-03 00:37:28 +0000241 def GetKeys(self, keySetName=None):
Steven M. Gava2a63a072001-10-26 06:50:54 +0000242 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000243 returns the requested keybindings, with fallbacks if required.
Steven M. Gava2a63a072001-10-26 06:50:54 +0000244 """
Steven M. Gava17d01542001-12-03 00:37:28 +0000245 #default keybindings.
246 #keybindings loaded from the config file(s) are loaded _over_ these
247 #defaults, so if there is a problem getting any binding there will
248 #be an 'ultimate last resort fallback' to the CUA-ish bindings
249 #defined here.
250 keyBindings={
251 '<<Copy>>': ['<Control-c>', '<Control-C>'],
252 '<<Cut>>': ['<Control-x>', '<Control-X>'],
253 '<<Paste>>': ['<Control-v>', '<Control-V>'],
254 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
255 '<<center-insert>>': ['<Control-l>'],
256 '<<close-all-windows>>': ['<Control-q>'],
257 '<<close-window>>': ['<Alt-F4>'],
258 '<<dump-undo-state>>': ['<Control-backslash>'],
259 '<<end-of-file>>': ['<Control-d>'],
260 '<<python-docs>>': ['<F1>'],
261 '<<python-context-help>>': ['<Shift-F1>'],
262 '<<history-next>>': ['<Alt-n>'],
263 '<<history-previous>>': ['<Alt-p>'],
264 '<<interrupt-execution>>': ['<Control-c>'],
265 '<<open-class-browser>>': ['<Alt-c>'],
266 '<<open-module>>': ['<Alt-m>'],
267 '<<open-new-window>>': ['<Control-n>'],
268 '<<open-window-from-file>>': ['<Control-o>'],
269 '<<plain-newline-and-indent>>': ['<Control-j>'],
270 '<<redo>>': ['<Control-y>'],
271 '<<remove-selection>>': ['<Escape>'],
272 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
273 '<<save-window-as-file>>': ['<Alt-s>'],
274 '<<save-window>>': ['<Control-s>'],
275 '<<select-all>>': ['<Alt-a>'],
276 '<<toggle-auto-coloring>>': ['<Control-slash>'],
277 '<<undo>>': ['<Control-z>']}
278 if keySetName:
279 pass
280
281 return keyBindings
282
Steven M. Gava2a63a072001-10-26 06:50:54 +0000283
Steven M. Gavac11ccf32001-09-24 09:43:17 +0000284 def LoadCfgFiles(self):
285 """
286 load all configuration files.
287 """
288 for key in self.defaultCfg.keys():
289 self.defaultCfg[key].Load()
290 self.userCfg[key].Load() #same keys
291
292 def SaveUserCfgFiles(self):
293 """
294 write all loaded user configuration files back to disk
295 """
296 for key in self.userCfg.keys():
297 self.userCfg[key].Save()
298
299idleConf=IdleConf()
300
301### module test
302if __name__ == '__main__':
303 def dumpCfg(cfg):
304 print '\n',cfg,'\n'
305 for key in cfg.keys():
306 sections=cfg[key].sections()
307 print key
308 print sections
309 for section in sections:
310 options=cfg[key].options(section)
311 print section
312 print options
313 for option in options:
314 print option, '=', cfg[key].Get(section,option)
315 dumpCfg(idleConf.defaultCfg)
316 dumpCfg(idleConf.userCfg)
317 print idleConf.userCfg['main'].Get('Theme','name')
318 #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')