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.shto 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. classattributes cannot contain leading or trailing whitespace.- Selectors must avoid matching more qualified scope-lists.
E.g.,variable.othershould 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.