Skip to content

Commit

Permalink
Fixed #12112 -- Made the colors used by syntax highlighting customiza…
Browse files Browse the repository at this point in the history
…ble.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12009 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Dec 28, 2009
1 parent 9319f89 commit c38d66a
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 18 deletions.
26 changes: 16 additions & 10 deletions django/core/management/color.py
Expand Up @@ -2,6 +2,7 @@
Sets up the terminal color scheme.
"""

import os
import sys

from django.utils import termcolors
Expand All @@ -21,16 +22,21 @@ def supports_color():
def color_style():
"""Returns a Style object with the Django color scheme."""
if not supports_color():
return no_style()
class dummy: pass
style = dummy()
style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
style.NOTICE = termcolors.make_style(fg='red')
style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
style.SQL_COLTYPE = termcolors.make_style(fg='green')
style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
style.SQL_TABLE = termcolors.make_style(opts=('bold',))
style = no_style()
else:
DJANGO_COLORS = os.environ.get('DJANGO_COLORS', '')
color_settings = termcolors.parse_color_setting(DJANGO_COLORS)
if color_settings:
class dummy: pass
style = dummy()
# The nocolor palette has all available roles.
# Use that pallete as the basis for populating
# the palette as defined in the environment.
for role in termcolors.PALETTES[termcolors.NOCOLOR_PALETTE]:
format = color_settings.get(role,{})
setattr(style, role, termcolors.make_style(**format))
else:
style = no_style()
return style

def no_style():
Expand Down
110 changes: 109 additions & 1 deletion django/utils/termcolors.py
Expand Up @@ -5,7 +5,6 @@
color_names = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
foreground = dict([(color_names[x], '3%s' % x) for x in range(8)])
background = dict([(color_names[x], '4%s' % x) for x in range(8)])
del color_names

RESET = '0'
opt_dict = {'bold': '1', 'underscore': '4', 'blink': '5', 'reverse': '7', 'conceal': '8'}
Expand Down Expand Up @@ -66,3 +65,112 @@ def make_style(opts=(), **kwargs):
COMMENT = make_style(fg='blue', opts=('bold',))
"""
return lambda text: colorize(text, opts, **kwargs)

NOCOLOR_PALETTE = 'nocolor'
DARK_PALETTE = 'dark'
LIGHT_PALETTE = 'light'

PALETTES = {
NOCOLOR_PALETTE: {
'ERROR': {},
'NOTICE': {},
'SQL_FIELD': {},
'SQL_COLTYPE': {},
'SQL_KEYWORD': {},
'SQL_TABLE': {},
},
DARK_PALETTE: {
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
'NOTICE': { 'fg': 'red' },
'SQL_FIELD': { 'fg': 'green', 'opts': ('bold',) },
'SQL_COLTYPE': { 'fg': 'green' },
'SQL_KEYWORD': { 'fg': 'yellow' },
'SQL_TABLE': { 'opts': ('bold',) },
},
LIGHT_PALETTE: {
'ERROR': { 'fg': 'red', 'opts': ('bold',) },
'NOTICE': { 'fg': 'red' },
'SQL_FIELD': { 'fg': 'green', 'opts': ('bold',) },
'SQL_COLTYPE': { 'fg': 'green' },
'SQL_KEYWORD': { 'fg': 'blue' },
'SQL_TABLE': { 'opts': ('bold',) },
}
}
DEFAULT_PALETTE = DARK_PALETTE

def parse_color_setting(config_string):
"""Parse a DJANGO_COLORS environment variable to produce the system palette
The general form of a pallete definition is:
"palette;role=fg;role=fg/bg;role=fg,option,option;role=fg/bg,option,option"
where:
palette is a named palette; one of 'light', 'dark', or 'nocolor'.
role is a named style used by Django
fg is a background color.
bg is a background color.
option is a display options.
Specifying a named palette is the same as manually specifying the individual
definitions for each role. Any individual definitions following the pallete
definition will augment the base palette definition.
Valid roles:
'error', 'notice', 'sql_field', 'sql_coltype', 'sql_keyword', 'sql_table'
Valid colors:
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
Valid options:
'bold', 'underscore', 'blink', 'reverse', 'conceal'
"""
if not config_string:
return PALETTES[DEFAULT_PALETTE]

# Split the color configuration into parts
parts = config_string.lower().split(';')
palette = PALETTES[NOCOLOR_PALETTE].copy()
for part in parts:
if part in PALETTES:
# A default palette has been specified
palette.update(PALETTES[part])
elif '=' in part:
# Process a palette defining string
definition = {}

# Break the definition into the role,
# plus the list of specific instructions.
# The role must be in upper case
role, instructions = part.split('=')
role = role.upper()

styles = instructions.split(',')
styles.reverse()

# The first instruction can contain a slash
# to break apart fg/bg.
colors = styles.pop().split('/')
colors.reverse()
fg = colors.pop()
if fg in color_names:
definition['fg'] = fg
if colors and colors[-1] in color_names:
definition['bg'] = colors[-1]

# All remaining instructions are options
opts = tuple(s for s in styles if s in opt_dict.keys())
if opts:
definition['opts'] = opts

# The nocolor palette has all available roles.
# Use that palette as the basis for determining
# if the role is valid.
if role in PALETTES[NOCOLOR_PALETTE] and definition:
palette[role] = definition

# If there are no colors specified, return the empty palette.
if palette == PALETTES[NOCOLOR_PALETTE]:
return None
return palette
87 changes: 83 additions & 4 deletions docs/ref/django-admin.txt
Expand Up @@ -991,13 +991,92 @@ being executed as an unattended, automated script.
Extra niceties
==============

.. _syntax-coloring:

Syntax coloring
---------------

The ``django-admin.py`` / ``manage.py`` commands that output SQL to standard
output will use pretty color-coded output if your terminal supports
ANSI-colored output. It won't use the color codes if you're piping the
command's output to another program.
The ``django-admin.py`` / ``manage.py`` commands that output SQL to
standard output will use pretty color-coded output if your terminal
supports ANSI-colored output. It won't use the color codes if you're
piping the command's output to another program.

The colors used for syntax highlighting can be customized. Django
ships with three color palettes:

* ``dark``, suited to terminals that show white text on a black
background. This is the default palette.

* ``light``, suited to terminals that show white text on a black
background.

* ``nocolor``, which disables syntax highlighting.

You select a palette by setting a ``DJANGO_COLORS`` environment
variable to specify the palette you want to use. For example, to
specify the ``light`` palette under a Unix or OS/X BASH shell, you
would run the following at a command prompt::

export DJANGO_COLORS="light"

You can also customize the colors that are used. Django specifies a
number of roles in which color is used:

* ``error`` - A major error.
* ``notice`` - A minor error.
* ``sql_field`` - The name of a model field in SQL.
* ``sql_coltype`` - The type of a model field in SQL.
* ``sql_keyword`` - A SQL keyword.
* ``sql_table`` - The name of a model in SQL.

Each of these roles can be assigned a specific foreground and
background color, from the following list:

* ``black``
* ``red``
* ``green``
* ``yellow``
* ``blue``
* ``magenta``
* ``cyan``
* ``white``

Each of these colors can then be modified by using the following
display options:

* ``bold``
* ``underscore``
* ``blink``
* ``reverse``
* ``conceal``

A color specification follows one of the the following patterns:

* ``role=fg``
* ``role=fg/bg``
* ``role=fg,option,option``
* ``role=fg/bg,option,option``

where ``role`` is the name of a valid color role, ``fg`` is the
foreground color, ``bg`` is the background color and each ``option``
is one of the color modifying options. Multiple color specifications
are then separated by semicolon. For example::

export DJANGO_COLORS="error=yellow/blue,blink;notice=magenta"

would specify that errors be displayed using blinking yellow on blue,
and notices displayed using magenta. All other color roles would be
left uncolored.

Colors can also be specified by extending a base palette. If you put
a palette name in a color specification, all the colors implied by that
palette will be loaded. So::

export DJANGO_COLORS="light;error=yellow/blue,blink;notice=magenta"

would specify the use of all the colors in the light color palette,
*except* for the colors for errors and notices which would be
overridden as specified.

Bash completion
---------------
Expand Down
11 changes: 9 additions & 2 deletions docs/releases/1.2.txt
Expand Up @@ -472,8 +472,8 @@ Fast Failure for Tests
----------------------

The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script
used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after
used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after
encountering a failure instead of continuing with the test run.

Improved localization
Expand All @@ -492,3 +492,10 @@ Added ``readonly_fields`` to ``ModelAdmin``
:attr:`django.contrib.admin.ModelAdmin.readonly_fields` has been added to
enable non-editable fields in add/change pages for models and inlines. Field
and calculated values can be displayed along side editable fields.

Customizable syntax highlighting
--------------------------------

You can now use the ``DJANGO_COLORS`` environment variable to modify
or disable the colors used by ``django-admin.py`` to provide
:ref:`syntax highlighting <syntax-coloring>`.

0 comments on commit c38d66a

Please sign in to comment.