Permalink
Browse files

exposed pygments styles as ipythonqt options

  • Loading branch information...
minrk committed Oct 14, 2010
1 parent dc30bee commit 8d603c09dd49e685cb5dae9c2e3e5dcf75a9a72a
@@ -25,33 +25,13 @@
from IPython.core.usage import default_gui_banner
from IPython.utils.traitlets import Bool, Str
from frontend_widget import FrontendWidget
+from styles import (default_light_style_sheet, default_dark_style_sheet,
+ default_light_syntax_style, default_dark_syntax_style)
#-----------------------------------------------------------------------------
# Constants
#-----------------------------------------------------------------------------
-# The default light style sheet: black text on a white background.
-default_light_style_sheet = '''
- .error { color: red; }
- .in-prompt { color: navy; }
- .in-prompt-number { font-weight: bold; }
- .out-prompt { color: darkred; }
- .out-prompt-number { font-weight: bold; }
-'''
-default_light_syntax_style = 'default'
-
-# The default dark style sheet: white text on a black background.
-default_dark_style_sheet = '''
- QPlainTextEdit, QTextEdit { background-color: black; color: white }
- QFrame { border: 1px solid grey; }
- .error { color: red; }
- .in-prompt { color: lime; }
- .in-prompt-number { color: lime; font-weight: bold; }
- .out-prompt { color: red; }
- .out-prompt-number { color: red; font-weight: bold; }
-'''
-default_dark_syntax_style = 'monokai'
-
# Default strings to build and display input and output prompts (and separators
# in between)
default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
@@ -7,12 +7,13 @@
# Systemm library imports
from PyQt4 import QtGui
-
+from pygments.styles import get_all_styles
# Local imports
from IPython.external.argparse import ArgumentParser
from IPython.frontend.qt.console.frontend_widget import FrontendWidget
from IPython.frontend.qt.console.ipython_widget import IPythonWidget
from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
+from IPython.frontend.qt.console import styles
from IPython.frontend.qt.kernelmanager import QtKernelManager
#-----------------------------------------------------------------------------
@@ -129,7 +130,7 @@ def main():
kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
help='set the REP channel port [default random]')
kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
- help='set the heartbeat port [default: random]')
+ help='set the heartbeat port [default random]')
egroup = kgroup.add_mutually_exclusive_group()
egroup.add_argument('--pure', action='store_true', help = \
@@ -148,6 +149,14 @@ def main():
help='enable rich text support')
wgroup.add_argument('--gui-completion', action='store_true',
help='use a GUI widget for tab completion')
+ wgroup.add_argument('--style', type=str,
+ help='specify a pygments style by name. \
+ Valid are: %s'%(list(get_all_styles())))
+ wgroup.add_argument('--stylesheet', type=str,
+ help="path to a custom CSS stylesheet.")
+ wgroup.add_argument('--dark', action='store_true',
+ help="use the dark style template instead of lightbg.\
+ If --style is not specified, the default dark style is used.")
args = parser.parse_args()
@@ -186,6 +195,33 @@ def main():
widget.gui_completion = args.gui_completion
widget.kernel_manager = kernel_manager
+ # configure the style:
+ if not args.pure: # only IPythonWidget supports styles
+ if args.style:
+ # guess whether it's a dark style:
+ dark = args.dark or styles.dark_style(args.style)
+ widget.syntax_style = args.style
+ widget.style_sheet = styles.sheet_from_template(args.style, not dark)
+ widget._syntax_style_changed()
+ widget._style_sheet_changed()
+ elif args.dark:
+ # use default dark style
+ widget.set_default_style(lightbg=False)
+ else:
+ # this is redundant for now, but allows the widget's
+ # defaults to change
+ widget.set_default_style(lightbg=True)
+
+ if args.stylesheet:
+ # we got an expicit stylesheet
+ if os.path.isfile(args.stylesheet):
+ with open(args.stylesheet) as f:
+ sheet = f.read()
+ widget.style_sheet = sheet
+ widget._style_sheet_changed()
+ else:
+ raise IOError("Stylesheet %r not found."%args.stylesheet)
+
# Create the main window.
window = MainWindow(app, widget, args.existing, may_close=local_kernel)
window.setWindowTitle('Python' if args.pure else 'IPython')
@@ -0,0 +1,102 @@
+""" Style utilities, templates, and defaults for syntax highlighting widgets.
+"""
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+from colorsys import rgb_to_hls
+from pygments.styles import get_style_by_name
+from pygments.token import Token
+
+#-----------------------------------------------------------------------------
+# Constants
+#-----------------------------------------------------------------------------
+
+# The default light style sheet: black text on a white background.
+default_light_style_template = '''
+ QPlainTextEdit, QTextEdit { background-color: %(bgcolor)s;
+ color: %(fgcolor)s ;
+ selection-background-color: %(select)s}
+ .error { color: red; }
+ .in-prompt { color: navy; }
+ .in-prompt-number { font-weight: bold; }
+ .out-prompt { color: darkred; }
+ .out-prompt-number { font-weight: bold; }
+'''
+default_light_style_sheet = default_light_style_template%dict(
+ bgcolor='white', fgcolor='black', select="#ccc")
+default_light_syntax_style = 'default'
+
+# The default dark style sheet: white text on a black background.
+default_dark_style_template = '''
+ QPlainTextEdit, QTextEdit { background-color: %(bgcolor)s;
+ color: %(fgcolor)s ;
+ selection-background-color: %(select)s}
+ QFrame { border: 1px solid grey; }
+ .error { color: red; }
+ .in-prompt { color: lime; }
+ .in-prompt-number { color: lime; font-weight: bold; }
+ .out-prompt { color: red; }
+ .out-prompt-number { color: red; font-weight: bold; }
+'''
+default_dark_style_sheet = default_dark_style_template%dict(
+ bgcolor='black', fgcolor='white', select="#555")
+default_dark_syntax_style = 'monokai'
+
+def hex_to_rgb(color):
+ """Convert a hex color to rgb integer tuple."""
+ if color.startswith('#'):
+ color = color[1:]
+ if len(color) == 3:
+ color = ''.join([c*2 for c in color])
+ if len(color) != 6:
+ return False
+ try:
+ r = int(color[:2],16)
+ g = int(color[:2],16)
+ b = int(color[:2],16)
+ except ValueError:
+ return False
+ else:
+ return r,g,b
+
+def dark_color(color):
+ """Check whether a color is 'dark'.
+
+ Currently, this is simply whether the luminance is <50%"""
+ rgb = hex_to_rgb(color)
+ if rgb:
+ return rgb_to_hls(*rgb)[1] < 128
+ else: # default to False
+ return False
+
+def dark_style(stylename):
+ """Guess whether the background of the style with name 'stylename'
+ counts as 'dark'."""
+ return dark_color(get_style_by_name(stylename).background_color)
+
+def get_colors(stylename):
+ """Construct the keys to be used building the base stylesheet."""
+ style = get_style_by_name(stylename)
+ fgcolor = style.style_for_token(Token.Text)['color'] or ''
+ if len(fgcolor) in (3,6):
+ # could be 'abcdef' or 'ace' hex, which needs '#' prefix
+ try:
+ int(fgcolor, 16)
+ except TypeError:
+ pass
+ else:
+ fgcolor = "#"+fgcolor
+
+ return dict(
+ bgcolor = style.background_color,
+ select = style.highlight_color,
+ fgcolor = fgcolor
+ )
+
+def sheet_from_template(name, lightbg=True):
+ """Use one of the base templates, and set bg/fg/select colors."""
+ if lightbg:
+ return default_light_style_template%get_colors(name)
+ else:
+ return default_dark_style_template%get_colors(name)

0 comments on commit 8d603c0

Please sign in to comment.