1+ from __future__ import with_statement
12import os
23import sys
34from ConfigParser import ConfigParser
45from itertools import chain
56from bpython .keys import key_dispatch
6- import errno
77
88
99class Struct (object ):
1010 """Simple class for instantiating objects we can add arbitrary attributes
1111 to and use for various arbitrary things."""
1212
13+ def get_config_home ():
14+ """Returns the base directory for bpython's configuration files."""
15+ xdg_config_home = os .environ .get ('XDG_CONFIG_HOME' , '~/.config' )
16+ return os .path .join (xdg_config_home , 'bpython' )
17+
18+ def default_config_path ():
19+ """Returns bpython's default configuration file path."""
20+ return os .path .join (get_config_home (), 'config' )
1321
1422def fill_config_with_default_values (config , default_values ):
1523 for section in default_values .iterkeys ():
@@ -25,11 +33,11 @@ def loadini(struct, configfile):
2533 """Loads .ini configuration file and stores its values in struct"""
2634
2735 config_path = os .path .expanduser (configfile )
28- if not os .path .isfile (config_path ) and configfile == '~/.bpython/config' :
29- # FIXME: I decided ~/.bpython.ini was a crappy place for a config file,
30- # so this is just a fallback if the default is passed - remove this
31- # eventually please .
32- config_path = os .path .expanduser ('~/.bpython.ini ' )
36+ if not os .path .isfile (config_path ) and configfile == default_config_path () :
37+ # We decided that ' ~/.bpython/config' still was a crappy
38+ # place, use XDG Base Directory Specification instead. Fall
39+ # back to old config, though .
40+ config_path = os .path .expanduser ('~/.bpython/config ' )
3341
3442 config = ConfigParser ()
3543 fill_config_with_default_values (config , {
@@ -69,7 +77,13 @@ def loadini(struct, configfile):
6977 'gtk' : {
7078 'font' : 'monospace 10' ,
7179 'color_scheme' : 'default' }})
72- config .read (config_path )
80+ if not config .read (config_path ):
81+ # No config file. If the user has it in the old place then complain
82+ if os .path .isfile (os .path .expanduser ('~/.bpython.ini' )):
83+ sys .stderr .write ("Error: It seems that you have a config file at "
84+ "~/.bpython.ini. Please move your config file to "
85+ "%s\n " % default_config_path ())
86+ sys .exit (1 )
7387
7488 struct .dedent_after = config .getint ('general' , 'dedent_after' )
7589 struct .tab_length = config .getint ('general' , 'tab_length' )
@@ -126,7 +140,7 @@ def loadini(struct, configfile):
126140 'prompt' : 'c' ,
127141 'prompt_more' : 'g' ,
128142 }
129-
143+
130144 default_gtk_colors = {
131145 'keyword' : 'b' ,
132146 'name' : 'k' ,
@@ -145,123 +159,61 @@ def loadini(struct, configfile):
145159 'prompt_more' : 'g' ,
146160 }
147161
148- # TODO consolidate
149162 if color_scheme_name == 'default' :
150163 struct .color_scheme = default_colors
151164 else :
152- path = os .path .expanduser ('~/.bpython/%s.theme' % (color_scheme_name ,))
153- load_theme (struct , path , config_path , default_colors )
165+ struct .color_scheme = dict ()
166+
167+ theme_filename = color_scheme_name + '.theme'
168+ path = os .path .expanduser (os .path .join (get_config_home (),
169+ theme_filename ))
170+ old_path = os .path .expanduser (os .path .join ('~/.bpython' ,
171+ theme_filename ))
172+
173+ for path in [path , old_path ]:
174+ try :
175+ load_theme (struct , path , struct .color_scheme , default_colors )
176+ except EnvironmentError :
177+ continue
178+ else :
179+ break
180+ else :
181+ sys .stderr .write ("Could not load theme '%s'.\n " %
182+ (color_scheme_name , ))
183+ sys .exit (1 )
154184
155185 if color_gtk_scheme_name == 'default' :
156186 struct .color_gtk_scheme = default_gtk_colors
157187 else :
158- path = os .path .expanduser ('~/.bpython/%s.theme' % (color_gtk_scheme_name ,))
159- load_gtk_theme (struct , path , config_path , default_gtk_colors )
160-
188+ struct .color_gtk_scheme = dict ()
189+ # Note: This is a new config option, hence we don't have a
190+ # fallback directory.
191+ path = os .path .expanduser (os .path .join (get_config_home (),
192+ color_gtk_scheme_name + '.theme' ))
193+
194+ try :
195+ load_theme (struct , path , struct .color_gtk_scheme , default_colors )
196+ except EnvironmentError :
197+ sys .stderr .write ("Could not load gtk theme '%s'.\n " %
198+ (color_gtk_scheme_name , ))
199+ sys .exit (1 )
161200
162201 # checks for valid key configuration this part still sucks
163202 for key in (struct .pastebin_key , struct .save_key ):
164203 key_dispatch [key ]
165204
166- # TODO consolidate
167- def load_theme (struct , path , inipath , default_colors ):
205+ def load_theme (struct , path , colors , default_colors ):
168206 theme = ConfigParser ()
169- try :
170- f = open (path , 'r' )
171- except (IOError , OSError ), e :
172- sys .stdout .write ("Error loading theme file specified in '%s':\n %s\n " %
173- (inipath , e ))
174- sys .exit (1 )
175- theme .readfp (f )
176- struct .color_scheme = {}
207+ with open (path , 'r' ) as f :
208+ theme .readfp (f )
177209 for k , v in chain (theme .items ('syntax' ), theme .items ('interface' )):
178210 if theme .has_option ('syntax' , k ):
179- struct . color_scheme [k ] = theme .get ('syntax' , k )
211+ colors [k ] = theme .get ('syntax' , k )
180212 else :
181- struct . color_scheme [k ] = theme .get ('interface' , k )
213+ colors [k ] = theme .get ('interface' , k )
182214
183215 # Check against default theme to see if all values are defined
184216 for k , v in default_colors .iteritems ():
185- if k not in struct .color_scheme :
186- struct .color_scheme [k ] = v
187- f .close ()
188-
189-
190- def load_gtk_theme (struct , path , inipath , default_colors ):
191- theme = ConfigParser ()
192- try :
193- f = open (path , 'r' )
194- except (IOError , OSError ), e :
195- sys .stdout .write ("Error loading theme file specified in '%s':\n %s\n " %
196- (inipath , e ))
197- sys .exit (1 )
198- theme .readfp (f )
199- struct .color_gtk_scheme = {}
200- for k , v in chain (theme .items ('syntax' ), theme .items ('interface' )):
201- if theme .has_option ('syntax' , k ):
202- struct .color_gtk_scheme [k ] = theme .get ('syntax' , k )
203- else :
204- struct .color_gtk_scheme [k ] = theme .get ('interface' , k )
205-
206- # Check against default theme to see if all values are defined
207- for k , v in default_colors .iteritems ():
208- if k not in struct .color_gtk_scheme :
209- struct .color_gtk_scheme [k ] = v
210- f .close ()
211-
212-
213-
214- def migrate_rc (path ):
215- """Use the shlex module to convert the old configuration file to the new
216- format.
217- The old configuration file is renamed but not removed by now."""
218- import shlex
219- f = open (path )
220- parser = shlex .shlex (f )
221-
222- bools = {
223- 'true' : True ,
224- 'yes' : True ,
225- 'on' : True ,
226- 'false' : False ,
227- 'no' : False ,
228- 'off' : False }
229-
230- config = ConfigParser ()
231- config .add_section ('general' )
232-
233- while True :
234- k = parser .get_token ()
235- v = None
236-
237- if not k :
238- break
239-
240- k = k .lower ()
241-
242- if parser .get_token () == '=' :
243- v = parser .get_token () or None
244-
245- if v is not None :
246- try :
247- v = int (v )
248- except ValueError :
249- if v .lower () in bools :
250- v = bools [v .lower ()]
251- config .set ('general' , k , v )
252- f .close ()
253- try :
254- os .makedirs (os .path .expanduser ('~/.bpython' ))
255- except OSError , e :
256- if e .errno != errno .EEXIST :
257- raise
258- f = open (os .path .expanduser ('~/.bpython/config' ), 'w' )
259- config .write (f )
217+ if k not in colors :
218+ colors [k ] = v
260219 f .close ()
261- os .rename (path , os .path .expanduser ('~/.bpythonrc.bak' ))
262- print ("The configuration file for bpython has been changed. A new "
263- "config file has been created as ~/.bpython/config" )
264- print ("The existing .bpythonrc file has been renamed to .bpythonrc.bak "
265- "and it can be removed." )
266- print "Press enter to continue."
267- raw_input ()
0 commit comments