GitHub syntax theme for Atom
This is a syntax highlighting theme for Atom that replicates the exact appearance of highlighted source-code on GitHub.com. It was created to facilitate development of TextMate-compatible grammars for use on GitHub.
Features
- Automatic dark-mode detected from system settings.
- Support for high-contrast and “dimmed” theme variants.
- Support for colourblind users (protanopia and deuteranopia)
- Pathologically-accurate highlighting (see next section)
- Automated styling updates; run
tools/update-styles.sh
to update CSS.
To-do list
TextMate vs CSS
TextMate Scope Selectors are not completely compatible with CSS classes, despite sharing a superficial resemblance:
.string.quoted.double CSS
string.quoted.double TextMate
In CSS, the order in which classes are listed in a class selector is irrelevant:
.string.quoted.double
is behaves the same as .double.quoted.string
. TextMate
selectors, however, are sensitive to the order in which scopes are listed, which
means string.quoted
matches string.quoted.double
but not quoted.string
,
string.foo.quoted
, or even foo.string.quoted
.
Why is this relevant?
GitHub uses TextMate selectors to map tokenised scope-lists onto CSS classes. In rare cases, a grammar might specify a scope-list that TextMate and CSS selectors interpret differently. For example, consider the following pattern:
name: "variable.global.other"
match: /\$\w+/
GitHub recognises both the variable
and variable.other
scopes, and assigns a
different colour to each. On GitHub, the aforementioned rule will be highlighted
as the former (variable
), whereas a naïve theme targeting .variable.other
in
CSS will see the latter.
The solution
CSS provides no elegant way to implement an “order-dependent class selector”. An ugly alternative is to use attribute selectors instead:
// NB: This example omits the rebarbative `syntax--` prefix necessitated by Atom
:is([class="string quoted double"], [class^="string quoted double "]){
}
Astute authors will correctly note several limitations with this approach:
- Classes must be separated by a single space (
U+0020
) only.
Multiple spaces or other whitespace characters won't match. class
attributes cannot contain leading or trailing whitespace.- Selectors must avoid matching more qualified scope-lists.
E.g.,variable.other
should not inherit the styling applied tovariable
, or vice versa. This requires the inclusion of a:not()
qualifier for every conflicting scope-list. For example:// Target "string" scope, but not more qualified selectors // such as "string.quoted.double" or "string.quoted.single" :is([class^="string "]):not( [class^="string quoted double"], [class^="string quoted single"] ){ }
- The list of supported scopes must be known ahead-of-time.
This is stipulated by the previous point.
Thankfully, each constraint is satisfied by Atom's built-in use of Less for
generating stylesheets. A script is provided for regenerating the scope-map
variables listed in scope-map.less
.
Related links
- Live preview of all TextMate scopes supported by GitHub
- GitHub Lightshow, a webapp to preview the output of TextMate grammars on GitHub. Note that styling is not kept in-sync with the rest of the site, and is often outdated.
textmate(5)
man page documenting the TextMate grammar format.