The theme module

This module provides the Theme class, which provides text formatting properties based on the action (standard action) of a Token.

These properties can be used to colorize text according to a language definition.

By default, the properties are read from a normal CSS (Cascading StyleSheets) file and presented to the user of the Theme module through TextFormat objects, although other storage backends could be devised.

A Theme provides a textformat() for standard actions, and a baseformat() for general roles, such as "window", which denotes an editor window (or an encompassing DIV or PRE block in HTML), "selection", which is used for selected text, "current-line", which can highlight the current line the cursor is in in an editor.

From the TextFormat returned by baseformat("selection") and "current-line", in most cases only the background color will be used.

For the roles "window", "selection" and "current-line", the baseformat() method also accepts a state argument, which can be "default", "focus" or "disabled". A theme always supports the "default" state, but can provide separate colors for the "focus" or "disabled" state, which can be used to change the basic formatting in an editor window based on its state (in keyboard focus or disabled). If a theme does not support the "disabled" and/or "focus" state, the default scheme is used.

A Theme is loaded from a CSS file using:

>>> from parce.theme import Theme
>>> th = Theme('/path/to/my/custom.css')

Get a TextFormat for an action, use e.g.:

>>> f = th.textformat(String)
>>> f
<TextFormat color=Color(r=192, g=0, b=0, a=255)>

Multiple CSS files can be combined into one theme, and CSS rules can also be provided as plain text when instantiating a Theme.

Mapping actions to CSS classes

Standard actions are mapped to one or more CSS class names using css_class(); it uses the action itself and the actions it descends from. All CSS rules are combined, the one with the most matches comes first.

For example, Comment maps to the "comment" CSS class, and Number maps to "literal number" because Number is a descendant action of Literal.

Some actions might have the same name, e.g. Escape and String.Escape. Both match CSS rules with the .escape class selector, but a rule with .string.escape will have a higher precedence.

The order of the action names does not matter. E.g. an action Text.Comment will match exactly the same CSS rules as an action Comment.Text. So you should take some care when designing you action hierachy and not add too much base action types.

class AbstractTheme[source]

Bases: object

Defines the interface of a Theme as used by a formatter.

baseformat(role='window', state='default')[source]

Should return a text format for a specific role and a state.

textformat(action)[source]

Should return a text format for the specified action.

class Theme(*filenames, stylesheet='', basename='')[source]

Bases: parce.theme.AbstractTheme

A Theme maps a StandardAction to a TextFormat with CSS properties.

Zero or more filenames can be given, which are loaded after another. If the stylesheet text is given, it is added to the stylesheets loaded from the filename(s). (If the basename is given, it is used to resolve @import rules in the stylesheet text.)

property style

The stylesheet style rules (see css.Style).

filenames()[source]

Return the list of filenames of the used stylesheet when instantiated

baseformat(role='window', state='default')[source]

Return a TextFormat for a specific role and a state.

The role may be any string that maps to a CSS class in the theme CSS file that is available there together with the parce class.

The following roles are recognized and used by parce, but you may also define your own roles in your (applications’) theme CSS files:

"window"

The TextFormat for the editor window or the encompassing DIV when formatting HTML. Corresponds to the “parce” CSS class alone in the theme file. You can set color, background and, if desired, font preferences.

"selection"

The TextFormat to use for selected text. Uses the ::selection pseudo element.

"current-line"

The TextFormat for the current line. If you use it, set only the background color in your theme file.

The state argument may be “default”, “focus”, or “disabled”, and reflects the state of the user interface the style variant is used for. If the state is “focus” or “disabled”, it is added as a pseudo class.

textformat(action)[source]

Return the TextFormat for the specified action.

class TextFormat(properties)[source]

Bases: object

Simple textformat that reads CSS properties and supports a subset of those.

This factory is used by default by Theme, but you can implement your own. Such a factory only needs to implement an __init__ method that reads the dictionary of property Value lists returned by Style.properties().

A TextFormat has a False boolean value if no single property is set.

You can add and subtract TextFormats:

>>> import parce
>>> t = parce.theme_by_name()
>>> f = t.baseformat()
>>> f
<TextFormat background_color=Color(r=255, g=255, b=240, a=1.0), color=
Color(r=0, g=0, b=0, a=1.0), font_family=['monospace'], font_size=12,
font_size_unit='pt'>
>>> f2 = t.textformat(parce.Comment)
>>> f2
<TextFormat color=Color(r=105, g=105, b=105, a=1.0), font_family=['serif'],
font_style='italic'>
>>> f + f2
<TextFormat background_color=Color(r=255, g=255, b=240, a=1.0), color=
Color(r=105, g=105, b=105, a=1.0), font_family=['serif'], font_size=12,
font_size_unit='pt', font_style='italic'>
>>> f - f2
<TextFormat background_color=Color(r=255, g=255, b=240, a=1.0), color=
Color(r=0, g=0, b=0, a=1.0), font_family=['monospace'], font_size=12,
font_size_unit='pt'>
>>>

Adding a TextFormat returns a new format with our properties set and then the properties of the other. This is useful when it is not possible to overlay properties with underlying window properties.

Subtracting a TextFormat returns a new format with the properties removed that are the same in the other format. This is useful when properties of a certain action happen to be the same as the underlying window properties; it is not needed to set these again in such cases.

color = None

the foreground color as Color(r, g, b, a) tuple

background_color = None

the background color (id)

caret_color = None

the color for the text cursor

text_decoration_color = None

the color for text decoration

text_decoration_line = ()

underline, overline and/or line-through

text_decoration_style = None

solid, double, dotted, dashed or wavy

font_family = ()

family or generic name

font_kerning = None

font kerning

font_size = None

font size

font_size_unit = None

font size unit if given

font_stretch = None

font stretch value (keyword or float, 1.0 is normal)

font_style = None

normal, italic or oblique

font_style_angle = None

oblique slant if given

font_style_angle_unit = None

oblique slant unit if given

font_variant_caps = None

all kind of small caps

font_variant_position = None

normal, sub or super

font_weight = None

100 - 900 or keyword like bold

css_properties()[source]

Return a dict usable to write out a CSS rule with our properties.

write_color()[source]

Yield color and background color as CSS properties, if set.

write_text_decoration()[source]

Yield a text-decoration property, if set.

write_font()[source]

Yield all font-xxxx properties, if set.

read_color(values)[source]
read_background_color(values)[source]
read_background(values)[source]
read_caret_color(values)[source]
read_text_decoration_color(values)[source]
read_text_decoration_line(values)[source]
read_text_decoration_style(values)[source]
read_text_decoration(values)[source]
read_font_family(values)[source]
read_font_kerning(values)[source]
read_font_size(values)[source]
read_font_stretch(values)[source]
read_font_style(values)[source]
read_font_variant_caps(values)[source]
read_font_variant_position(values)[source]
read_font_weight(values)[source]
read_font(values)[source]
css_class(action)[source]

Return a CSS class string for the specified standard action.

The class names are simply the name of the action and all its ancestor actions. Class names are lowercase and space-separated. For example:

>>> from parce.action import Number
>>> Number
Literal.Number
>>> css_class(Number)
'literal number'