4545import pydoc
4646import types
4747import unicodedata
48+ from itertools import chain
4849from cStringIO import StringIO
4950from locale import LC_ALL , getpreferredencoding , setlocale
5051from optparse import OptionParser
@@ -133,54 +134,14 @@ def DEBUG(s):
133134 open ('/tmp/bpython-debug' , 'a' ).write ("%s\n " % (str (s ), ))
134135
135136
136- def make_colours ( ):
137- """Init all the colours in curses and bang them into a dictionary"""
137+ def get_color ( name ):
138+ return colors [ OPTS . color_scheme [ name ]]
138139
139- OPTS .light = {
140- 'listwin' : 'b' ,
141- 'args' : 'g' ,
142- 'kwvalue' : 'b' ,
143- 'self' : 'r' ,
144- '*args' : 'g' ,
145- '**kwargs' : 'g' ,
146- 'punctuation' : 'k' ,
147- 'paren' : 'y' ,
148- 'function' : 'r' ,
149- 'more' : 'g' ,
150- 'prompt' : 'r' ,
151- 'output' : 'k' ,
152- 'statusbar' : 'r' ,
153- 'error' : 'b' ,
154- }
155- OPTS .dark = {
156- 'listwin' : 'c' ,
157- 'args' : 'g' ,
158- 'kwvalue' : 'b' ,
159- 'self' : 'r' ,
160- '*args' : 'g' ,
161- '**kwargs' : 'g' ,
162- 'punctuation' : 'm' ,
163- 'paren' : 'y' ,
164- 'function' : 'r' ,
165- 'more' : 'y' ,
166- 'prompt' : 'g' ,
167- 'output' : 'w' ,
168- 'statusbar' : 'c' ,
169- 'error' : 'y' ,
170- }
171- if OPTS .color_scheme == 'light' :
172- bg = 7
173- OPTS .extras = OPTS .light
174- else :
175- bg = 0
176- OPTS .extras = OPTS .dark
140+ def get_colpair (name ):
141+ return curses .color_pair (get_color (name ) + 1 )
177142
178- for i in range (63 ):
179- if i > 7 :
180- j = i / 8
181- else :
182- j = bg
183- curses .init_pair (i + 1 , i % 8 , j )
143+ def make_colors ():
144+ """Init all the colours in curses and bang them into a dictionary"""
184145
185146 # blacK, Red, Green, Yellow, Blue, Magenta, Cyan, White, Default:
186147 c = {
@@ -194,7 +155,13 @@ def make_colours():
194155 'w' : 7 ,
195156 'd' : - 1 ,
196157 }
197- c .update ((k , c [v ]) for k , v in OPTS .extras .iteritems ())
158+ for i in range (63 ):
159+ if i > 7 :
160+ j = i / 8
161+ else :
162+ j = c [OPTS .color_scheme ['background' ]]
163+ curses .init_pair (i + 1 , i % 8 , j )
164+
198165 return c
199166
200167
@@ -275,7 +242,7 @@ def showtraceback(self):
275242 def writetb (self , l ):
276243 """This outputs the traceback and should be overridden for anything
277244 fancy."""
278- map (self .write , ["\x01 %s\x03 %s" % (OPTS .extras ['error' ], i ) for i in l ])
245+ map (self .write , ["\x01 %s\x03 %s" % (OPTS .color_scheme ['error' ], i ) for i in l ])
279246
280247
281248class Repl (object ):
@@ -714,9 +681,7 @@ def lsize():
714681
715682 for ix , i in enumerate (v_items ):
716683 padding = (wl - len (i )) * ' '
717- self .list_win .addstr (
718- i + padding ,
719- curses .color_pair (self ._C ["listwin" ]+ 1 ))
684+ self .list_win .addstr (i + padding , get_colpair ('main' ))
720685 if ((cols == 1 or (ix and not (ix + 1 ) % cols ))
721686 and ix + 1 < len (v_items )):
722687 self .list_win .addstr ('\n ' )
@@ -730,6 +695,7 @@ def lsize():
730695
731696 self .statusbar .win .touchwin ()
732697 self .statusbar .win .noutrefresh ()
698+ self .list_win .attron (get_colpair ('main' ))
733699 self .list_win .border ()
734700 self .scr .touchwin ()
735701 self .scr .cursyncup ()
@@ -761,8 +727,8 @@ def mkargspec(self, topline, down):
761727
762728 self .list_win .addstr ('\n ' )
763729 self .list_win .addstr (fn ,
764- curses . color_pair ( self . _C [ "function" ] + 1 ) | curses .A_BOLD )
765- self .list_win .addstr (': (' , curses . color_pair ( self . _C [ "paren" ] + 1 ))
730+ get_colpair ( 'name' ) | curses .A_BOLD )
731+ self .list_win .addstr (': (' , get_colpair ( 'name' ))
766732 maxh = self .scr .getmaxyx ()[0 ]
767733
768734 for k , i in enumerate (args ):
@@ -788,33 +754,27 @@ def mkargspec(self, topline, down):
788754 self .list_win .addstr ('\n \t ' )
789755
790756 if str (i ) == 'self' and k == 0 :
791- color = self . _C [ "self" ]
757+ color = get_colpair ( 'name' )
792758 else :
793- color = self . _C [ "args" ]
759+ color = get_colpair ( 'token' )
794760
795- self .list_win .addstr (str (i ),
796- curses .color_pair (color + 1 ) | curses .A_BOLD )
761+ self .list_win .addstr (str (i ), color | curses .A_BOLD )
797762 if kw :
798- self .list_win .addstr ('=' ,
799- curses .color_pair (self ._C ["punctuation" ]+ 1 ))
800- self .list_win .addstr (kw , curses .color_pair (self ._C ["kwvalue" ]+ 1 ))
763+ self .list_win .addstr ('=' , get_colpair ('punctuation' ))
764+ self .list_win .addstr (kw , get_colpair ('token' ))
801765 if k != len (args ) - 1 :
802- self .list_win .addstr (', ' ,
803- curses .color_pair (self ._C ["punctuation" ]+ 1 ))
766+ self .list_win .addstr (', ' , get_colpair ("punctuation" ))
804767
805768 if _args :
806769 if args :
807- self .list_win .addstr (', ' ,
808- curses .color_pair (self ._C ["args" ]+ 1 ))
809- self .list_win .addstr ('*%s' % (_args , ),
810- curses .color_pair (self ._C ["*args" ]+ 1 ))
770+ self .list_win .addstr (', ' , get_colpair ('punctuation' ))
771+ self .list_win .addstr ('*%s' % (_args , ), get_colpair ('token' ))
772+
811773 if _kwargs :
812774 if args or _args :
813- self .list_win .addstr (', ' ,
814- curses .color_pair (self ._C ["punctuation" ]+ 1 ))
815- self .list_win .addstr ('**%s' % (_kwargs , ),
816- curses .color_pair (self ._C ["**kwargs" ]+ 1 ))
817- self .list_win .addstr (')' , curses .color_pair (self ._C ["paren" ]+ 1 ))
775+ self .list_win .addstr (', ' , get_colpair ('punctuation' ))
776+ self .list_win .addstr ('**%s' % (_kwargs , ), get_colpair ('token' ))
777+ self .list_win .addstr (')' , get_colpair ('punctuation' ))
818778
819779 return r
820780
@@ -1008,13 +968,14 @@ def reevaluate(self):
1008968 def prompt (self , more ):
1009969 """Show the appropriate Python prompt"""
1010970 if not more :
1011- self .echo ("\x01 %s\x03 >>> " % (OPTS .extras ['prompt' ],))
971+ self .echo ("\x01 %s\x03 >>> " % (OPTS .color_scheme ['prompt' ],))
1012972 self .stdout_hist += '>>> '
1013- self .s_hist .append ('\x01 %s\x03 >>> \x04 ' % (OPTS .extras ['prompt' ],))
973+ self .s_hist .append ('\x01 %s\x03 >>> \x04 ' % (OPTS .color_scheme ['prompt' ],))
1014974 else :
1015- self .echo ("\x01 %s\x03 ... " % (OPTS .extras [ 'more ' ],))
975+ self .echo ("\x01 %s\x03 ... " % (OPTS .color_scheme [ 'prompt_more ' ],))
1016976 self .stdout_hist += '... '
1017- self .s_hist .append ('\x01 %s\x03 ... \x04 ' % (OPTS .extras ['more' ],))
977+ self .s_hist .append ('\x01 %s\x03 ... \x04 ' %
978+ (OPTS .color_scheme ['prompt_more' ],))
1018979
1019980 def repl (self ):
1020981 """Initialise the repl and jump into the loop. This method also has to
@@ -1136,7 +1097,7 @@ def echo(self, s, redraw=True):
11361097 if isinstance (s , unicode ):
11371098 s = s .encode (getpreferredencoding ())
11381099
1139- a = curses . color_pair ( colors [ OPTS . extras [ 'output' ]] + 1 )
1100+ a = get_colpair ( 'output' )
11401101 if '\x01 ' in s :
11411102 rx = re .search ('\x01 ([a-z])([a-z]?)' , s )
11421103 if rx :
@@ -1807,7 +1768,7 @@ def init_wins(scr, cols):
18071768#
18081769 statusbar = Statusbar (scr , main_win ,
18091770 ".:: <C-d> Exit <C-r> Rewind <F2> Save <F8> Pastebin ::." ,
1810- cols [OPTS .extras [ 'statusbar ' ]] + 1 )
1771+ cols [OPTS .color_scheme [ 'main ' ]] + 1 )
18111772
18121773 return main_win , statusbar
18131774
@@ -1915,30 +1876,32 @@ def migrate_rc(path):
19151876 config .write (f )
19161877 f .close ()
19171878 os .rename (path , os .path .expanduser ('~/.bpythonrc.bak' ))
1918- print "The configuration file for bpython has been changed. A new .bpython.ini file has been created in your home directory."
1919- print "The existing .bpythonrc file has been renamed to .bpythonrc.bak and it can be removed."
1879+ print ("The configuration file for bpython has been changed. A new "
1880+ ".bpython.ini file has been created in your home directory." )
1881+ print ("The existing .bpythonrc file has been renamed to .bpythonrc.bak "
1882+ "and it can be removed." )
19201883 print "Press enter to continue."
19211884 raw_input ()
19221885
19231886
1887+ class CP (ConfigParser ):
1888+ def safeget (self , section , option , default ):
1889+ """safet get method using default values"""
1890+ try :
1891+ v = self .get (section , option )
1892+ except NoSectionError :
1893+ v = default
1894+ except NoOptionError :
1895+ v = default
1896+ if isinstance (v , bool ):
1897+ return v
1898+ try :
1899+ return int (v )
1900+ except ValueError :
1901+ return v
19241902
19251903def loadini (configfile ):
19261904 """Loads .ini configuration file and stores its values in OPTS"""
1927- class CP (ConfigParser ):
1928- def safeget (self , section , option , default ):
1929- """safet get method using default values"""
1930- try :
1931- v = self .get (section , option )
1932- except NoSectionError :
1933- v = default
1934- except NoOptionError :
1935- v = default
1936- if isinstance (v , bool ):
1937- return v
1938- try :
1939- return int (v )
1940- except ValueError :
1941- return v
19421905
19431906 configfile = os .path .expanduser (configfile )
19441907
@@ -1952,7 +1915,43 @@ def safeget(self, section, option, default):
19521915 OPTS .hist_file = config .safeget ('general' , 'hist_file' , '~/.pythonhist' )
19531916 OPTS .hist_length = config .safeget ('general' , 'hist_length' , 100 )
19541917 OPTS .flush_output = config .safeget ('general' , 'flush_output' , True )
1955- OPTS .color_scheme = config .safeget ('general' , 'color_scheme' , 'dark' )
1918+ color_scheme_name = config .safeget ('general' , 'color_scheme' , 'default' )
1919+
1920+ if color_scheme_name == 'default' :
1921+ OPTS .color_scheme = {
1922+ 'keyword' : 'Y' ,
1923+ 'name' : 'B' ,
1924+ 'comment' : 'b' ,
1925+ 'string' : 'g' ,
1926+ 'error' : 'r' ,
1927+ 'number' : 'g' ,
1928+ 'operator' : 'c' ,
1929+ 'punctuation' : 'y' ,
1930+ 'token' : 'g' ,
1931+ 'background' : 'k' ,
1932+ 'output' : 'w' ,
1933+ 'main' : 'c' ,
1934+ 'prompt' : 'r' ,
1935+ 'prompt_more' : 'g' ,
1936+ }
1937+ else :
1938+ path = os .path .expanduser ('~/.bpython/%s.theme' % (color_scheme_name ,))
1939+ # XXX ConfigParser doesn't raise an IOError if it tries to read a file
1940+ # that doesn't exist which isn't helpful to us:
1941+ if not os .path .isfile (path ):
1942+ raise IOError ("'%s' is not a readable file" % (path ,))
1943+ load_theme (color_scheme_name )
1944+
1945+ def load_theme (name ):
1946+ path = os .path .expanduser ('~/.bpython/%s.theme' % (name ,))
1947+ theme = CP ()
1948+ theme .read (path )
1949+ OPTS .color_scheme = {}
1950+ for k , v in chain (theme .items ('syntax' ), theme .items ('interface' )):
1951+ if theme .has_option ('syntax' , k ):
1952+ OPTS .color_scheme [k ] = theme .get ('syntax' , k )
1953+ else :
1954+ OPTS .color_scheme [k ] = theme .get ('interface' , k )
19561955
19571956
19581957class FakeDict (object ):
@@ -1968,11 +1967,7 @@ def newwin(*args):
19681967 """Wrapper for curses.newwin to automatically set background colour on any
19691968 newly created window."""
19701969 win = curses .newwin (* args )
1971- if OPTS .color_scheme == 'light' :
1972- bg = colors ['w' ]
1973- else :
1974- bg = colors ['k' ]
1975- colpair = curses .color_pair (bg )
1970+ colpair = get_colpair ('background' )
19761971 win .bkgd (' ' , colpair )
19771972 return win
19781973
@@ -1998,7 +1993,7 @@ def main_curses(scr):
19981993 try :
19991994 curses .start_color ()
20001995 curses .use_default_colors ()
2001- cols = make_colours ()
1996+ cols = make_colors ()
20021997 except curses .error :
20031998 cols = FakeDict (- 1 )
20041999
0 commit comments