├── .eslintrc.json ├── .github └── CONTRIBUTING.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── lib ├── adapters │ ├── ace.js │ ├── atom.js │ ├── codemirror.js │ ├── css.js │ ├── index.js │ ├── tmtheme.js │ └── vscode.js ├── templates │ ├── atom │ │ ├── editor.less │ │ └── syntax-variables.less │ └── codemirror.scss ├── themes │ ├── dark.json │ ├── index.js │ └── light.json └── utils │ └── index.js ├── package.json └── test ├── accessibility.js └── utils └── header.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "eslint-plugin-github" 4 | ], 5 | "env": { 6 | "es6": true, 7 | "node": true 8 | }, 9 | "extends": [ 10 | "plugin:github/recommended", 11 | "plugin:github/es6" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | [fork]: https://github.com/github/github-syntax-theme/fork 4 | [pr]: https://github.com/github/github-syntax-theme/compare 5 | [style]: http://primercss.io/guidelines/ 6 | 7 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 8 | 9 | After you open your first pull request, you will be asked to accept [this license agreement](https://cla.github.com/). Let us know in the PR if you have any hesitation or concerns. 10 | 11 | ## Using the issue tracker 12 | 13 | The [issue tracker](https://github.com/github/github-syntax-theme/issues) is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests), but please respect the following restrictions: 14 | 15 | * Please **do not** use the issue tracker for personal support requests. 16 | * Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. 17 | 18 | ## Bug reports 19 | 20 | A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks! 21 | 22 | Guidelines for bug reports: 23 | 24 | 0. **Validate and lint your code** — [validate your HTML](http://html5.validator.nu) to ensure your problem isn't caused by a simple error in your own code. 25 | 26 | 1. **Use the GitHub issue search** — check if the issue has already been reported. 27 | 28 | 2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository. 29 | 30 | 3. **Isolate the problem** — ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live example. [This JS Bin](http://jsbin.com/lefey/1/edit?html,output) is a helpful template. 31 | 32 | A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and OS experience the problem? Do other browsers show the bug differently? What would you expect to be the outcome? All these details will help people to fix any potential bugs. 33 | 34 | Example: 35 | 36 | > Short and descriptive example bug report title 37 | > 38 | > A summary of the issue and the browser/OS environment in which it occurs. If 39 | > suitable, include the steps required to reproduce the bug. 40 | > 41 | > 1. This is the first step 42 | > 2. This is the second step 43 | > 3. Further steps, etc. 44 | > 45 | > `` - a link to the reduced test case 46 | > 47 | > Any other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits). 48 | 49 | ## Feature requests 50 | 51 | Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible. 52 | 53 | ## Pull requests 54 | 55 | Good pull requests—patches, improvements, new features—are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. 56 | 57 | **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. 58 | 59 | Adhering to the following process is the best way to get your work included in the project: 60 | 61 | 1. Fork and clone the repository 62 | 2. Configure and install the dependencies: `bower install` 63 | 3. Create a new branch: `git checkout -b my-branch-name` 64 | 4. Make your change, add tests, and make sure the tests still pass 65 | 5. Push to your fork and [submit a pull request](https://help.github.com/articles/creating-a-pull-request/) 66 | 6. Pat your self on the back and wait for your pull request to be reviewed and merged. 67 | 68 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 69 | 70 | - Follow the [style guide][style]. 71 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. 72 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 73 | 74 | ## Resources 75 | 76 | - [Contributing to Open Source on GitHub](https://guides.github.com/activities/contributing-to-open-source/) 77 | - [Using Pull Requests](https://help.github.com/articles/using-pull-requests/) 78 | - [GitHub Help](https://help.github.com) 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | *.log 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '7.2' 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.4.1 2 | 3 | - Updating light theme to reflect color system changes. 4 | 5 | # 0.3.2 6 | 7 | - Updating the atom script to not rely on the atom package manager converting a textmate theme. 8 | 9 | # 0.3.0 10 | 11 | - Adding carriage return content to output [#16](https://github.com/primer/github-syntax-theme-generator/pull/16) 12 | 13 | # 0.2.0 14 | 15 | - Accessibility contrast tests 16 | - Separating the themes (dark, light) into separate json objects. 17 | - Update themes to be more compatible with SublimeText 18 | 19 | # 0.1.2 20 | 21 | - Fixing: Ace adapter would error if build didn't exist yet. 22 | - Fixing: The dark mode lineHighlight and text selection wasn't optimized. 23 | 24 | # 0.1.1 25 | 26 | - Fixing a bug where the dark themes aren't built 27 | 28 | # 0.1.0 29 | 30 | - Initial release. Support for Ace, Atom, CSS, Textmate themes. 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 GitHub, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub syntax theme generators 2 | 3 | [![NPM version](https://img.shields.io/npm/v/github-syntax-theme-generator.svg)](https://www.npmjs.org/package/github-syntax-theme-generator) 4 | [![Build Status](https://travis-ci.org/primer/github-syntax-theme-generator.svg?branch=master)](https://travis-ci.org/primer/github-syntax-theme-generator) 5 | 6 | > The GitHub syntax theme generator will generate themes for multiple platforms based on the GitHub syntax theme. 7 | 8 | ## Install 9 | 10 | All of the built themes in this package are distributed at separate repositories. It's recommended that you install one of these if you're looking for a specific theme. 11 | 12 | ### CSS 13 | 14 | The CSS syntax theme is based on a custom syntax highlighter in use by GitHub. The prefixes to the classes are `.pl-` for Prettylights. 15 | 16 | - [github-syntax-light](https://github.com/primer/github-syntax-light) 17 | - [github-syntax-dark](https://github.com/primer/github-syntax-dark) 18 | 19 | ### [Codemirror][codemirror] 20 | 21 | The [Codemirror][codemirror] syntax theme is generated by the [codemirror](./lib/adapters/codemirror.js) adapter. 22 | 23 | - [codemirror-github-light](https://github.com/primer/codemirror-github-light) 24 | - [codemirror-github-dark](https://github.com/primer/codemirror-github-dark) 25 | 26 | ### [Atom][atom] 27 | 28 | The [Atom][atom] theme is built by `apm` converted from the [TextMate][tm] theme. 29 | 30 | - [github-atom-light-syntax](https://github.com/primer/github-atom-light-syntax) 31 | - [github-atom-dark-syntax](https://github.com/primer/github-atom-dark-syntax) 32 | 33 | ### [TextMate][tm] 34 | 35 | For [TextMate][tm] or any other TextMate compatible editors, you can use the [github-textmate-theme](https://github.com/primer/github-textmate-theme). 36 | 37 | 38 | ## Development 39 | 40 | Clone this repository and after `npm install`. Run 41 | 42 | ``` 43 | $ npm run build 44 | ``` 45 | 46 | This will run the script that will build all the themes. The themes are built from the `json` files in the `lib/themes` folder. 47 | 48 | ## Adapters 49 | 50 | The theme adapters are located in `./lib/adapters/` directory. Each one will complete a specific task to build that theme. 51 | 52 | ## Contributing 53 | 54 | If you would like to see the theme compiled for another platform, we welcome pull requests. 55 | 56 | ## License 57 | 58 | [MIT](./LICENSE) © [GitHub](https://github.com/) 59 | 60 | [vscode]: https://code.visualstudio.com/ 61 | [codemirror]: https://codemirror.net/ 62 | [tm]: https://github.com/textmate/textmate 63 | [atom]: https://atom.io/ 64 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const themes = require("./lib/themes") 2 | const adapters = require("./lib/adapters") 3 | 4 | themes.map(theme => { 5 | Object.keys(adapters).map(k => { 6 | const adapter = adapters[k] 7 | adapter.call(this, theme) 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /lib/adapters/ace.js: -------------------------------------------------------------------------------- 1 | const exec = require("child_process").exec 2 | const mkdirp = require("mkdirp") 3 | const fs = require("fs") 4 | const header = require("../utils").header 5 | 6 | module.exports = (theme) => { 7 | mkdirp.sync("build/ace") 8 | fs.exists("build/ace/" + theme.filename + ".css", exists => { 9 | if(exists) { 10 | fs.unlink("build/ace/" + theme.filename + ".css") 11 | } 12 | }) 13 | exec("node node_modules/ace/tool/tmtheme.js " + theme.filename + " \"build/tmtheme/" + theme.name + ".tmbundle/Themes/" + theme.name + ".tmTheme\" build/ace", (error, stdout, stderr) => { 14 | if (error) { 15 | throw error; 16 | } 17 | var css = fs.readFileSync("build/ace/" + theme.filename + ".css") 18 | var reg = new RegExp("\\.ace\-" + theme.filename + " ?\\.", "gi") 19 | css = css.toString().replace(reg, ".") 20 | css = header(theme) + css 21 | fs.writeFileSync("build/ace/" + theme.filename + ".css", css) 22 | fs.unlink("build/ace/" + theme.filename + ".js") 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /lib/adapters/atom.js: -------------------------------------------------------------------------------- 1 | const mkdirp = require("mkdirp") 2 | const fs = require("fs") 3 | const utils = require("../utils") 4 | 5 | function updateScope (scopeText) { 6 | return scopeText.split(" ") 7 | .map((scope) => { 8 | return scope.split(".") 9 | .map((scopePart) => { return `syntax--${scopePart}` }) 10 | .join(".") 11 | }) 12 | .join(" .") 13 | .split(", ") 14 | .join(",\n") 15 | } 16 | 17 | module.exports = (theme) => { 18 | mkdirp.sync(`build/atom/${theme.filename}`) 19 | 20 | let languages = "" 21 | let syntaxVariables = fs.readFileSync("./lib/templates/atom/syntax-variables.less").toString() 22 | const editor = fs.readFileSync("./lib/templates/atom/editor.less") 23 | 24 | theme.settings.forEach((setting) => { 25 | const settings = setting.settings 26 | const scope = setting.scope 27 | 28 | // Editor settings 29 | if (!scope) { 30 | Object.keys(settings).forEach((key) => { 31 | syntaxVariables = syntaxVariables.replace(new RegExp("\\${" + key + "}", "g"), settings[key]) 32 | }) 33 | } else { 34 | languages += `\n.${updateScope(scope)} {${utils.declarations(settings)}\n}\n` 35 | } 36 | }) 37 | 38 | fs.writeFileSync(`./build/atom/${theme.filename}/syntax-variables.less`, syntaxVariables) 39 | fs.writeFileSync(`./build/atom/${theme.filename}/editor.less`, editor) 40 | fs.writeFileSync(`./build/atom/${theme.filename}/languages.less`, `atom-text-editor {${languages}}`) 41 | } 42 | -------------------------------------------------------------------------------- /lib/adapters/codemirror.js: -------------------------------------------------------------------------------- 1 | const mkdirp = require("mkdirp") 2 | const fs = require("fs") 3 | const sass = require("node-sass") 4 | const utils = require("../utils") 5 | 6 | module.exports = (theme) => { 7 | mkdirp.sync(`build/codemirror`) 8 | 9 | let template = fs.readFileSync("./lib/templates/codemirror.scss").toString() 10 | let output = utils.header(theme) 11 | 12 | template = template.replace(new RegExp("\\${theme}", "g"), theme.filename) 13 | 14 | theme.settings.forEach((setting) => { 15 | const settings = setting.settings 16 | const scope = setting.scope 17 | 18 | // Editor settings 19 | if (!scope) { 20 | Object.keys(settings).forEach((key) => { 21 | template = template.replace(new RegExp("\\${" + key + "}", "g"), settings[key]) 22 | }) 23 | output += template 24 | } else { 25 | const singleScope = scope.split(", ")[0] 26 | if (singleScope && !singleScope.match(/[\.\s\-]/)) { 27 | output += `\n.cm-s-${theme.filename} .cm-${singleScope} { ${utils.declarations(settings)} }` 28 | } 29 | } 30 | }) 31 | 32 | const result = sass.renderSync({ 33 | data: output, 34 | includePaths: ["./node_modules"] 35 | }) 36 | fs.writeFileSync(`./build/codemirror/codemirror-${theme.filename}-theme.css`, result.css) 37 | } 38 | -------------------------------------------------------------------------------- /lib/adapters/css.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const _ = require("lodash") 3 | const mkdirp = require("mkdirp") 4 | const header = require("../utils").header 5 | 6 | module.exports = (theme) => { 7 | 8 | var settings = _.filter(theme.settings, t => { return t["scope"] != null }) 9 | 10 | var convertAttributes = a => { 11 | var attributes = {} 12 | switch (a.fontStyle) { 13 | case "bold": 14 | attributes["font-weight"] = "bold" 15 | break; 16 | case "italic": 17 | attributes["font-style"] = "italic" 18 | break; 19 | case "underline": 20 | attributes["text-decoration"] = "underline" 21 | break; 22 | } 23 | 24 | if (a.foreground) { 25 | attributes["color"] = a.foreground 26 | } 27 | 28 | if (a.background) { 29 | attributes["background-color"] = a.background 30 | } 31 | 32 | if (a.content) { 33 | attributes["content"] = a.content 34 | } 35 | 36 | return attributes 37 | } 38 | 39 | var generateScopeClass = (scope, classes) => { 40 | var candidate = "pl-" + scope.split(".").map( s => { return s[0]}).join("") 41 | var suffix = "" 42 | var cssClass = candidate + "" + suffix 43 | while(classes.indexOf(cssClass) >= 0) { 44 | var suffix = suffix || 0 45 | suffix++ 46 | cssClass = candidate + "" + suffix 47 | } 48 | classes.push(cssClass) 49 | return cssClass 50 | } 51 | 52 | var selectorsByStyle = {}, 53 | combinatorScopes = new Set(), 54 | classes = [], 55 | classesByScope = {} 56 | 57 | settings.map( t => { 58 | var style = convertAttributes(t.settings) 59 | 60 | var selectors = t.scope.split(",").map( s => { return s.trim() }) 61 | if (selectors.length != 0 && selectors != ["none"]) { 62 | 63 | selectorsByStyle[JSON.stringify(style)] = _.union(selectorsByStyle[JSON.stringify(style)], selectors) 64 | 65 | selectors.map( selector => { 66 | var scopes = selector.split(" ") 67 | if(scopes.length >= 2) { 68 | combinatorScopes = _.union(combinatorScopes, scopes) 69 | } 70 | }) 71 | } 72 | }) 73 | 74 | _.map(selectorsByStyle, (selectors, style) => { 75 | style = JSON.parse(style) 76 | 77 | var scopesWithoutClasses = _.difference(_.uniq(_.flattenDeep(selectors.map( l => { return l.split(" ") }))), Object.keys(classesByScope)) 78 | 79 | var sharedScopes = _.difference(scopesWithoutClasses, combinatorScopes) 80 | var uniqueScopes = _.intersection(scopesWithoutClasses, combinatorScopes) 81 | 82 | if (sharedScopes.length > 0) { 83 | var cssClass = generateScopeClass(sharedScopes.sort()[0], classes) 84 | sharedScopes.map( scope => { 85 | classesByScope[scope] = cssClass 86 | }) 87 | } 88 | 89 | uniqueScopes.map( scope => { 90 | classesByScope[scope] = generateScopeClass(scope, classes) 91 | }) 92 | }) 93 | 94 | rules = _.flatMap(selectorsByStyle, (selectors, style) => { 95 | style = JSON.parse(style) 96 | 97 | var scopeSelectorsByCss = _.groupBy(selectors, selector => { 98 | var scopes = selector.split(" ") 99 | classes = scopes.map( s => { return classesByScope[s] }) 100 | return classes.map( c => { return "." + c }).join(" ") 101 | }) 102 | 103 | var content 104 | if (style.content) { 105 | content = style.content; 106 | delete style.content; 107 | } 108 | 109 | const styles = [{ 110 | "style": style, 111 | "selectors": _.map(scopeSelectorsByCss, (scopes, css) => { return { "css": css, "scopes": scopes }}) 112 | }] 113 | 114 | if (content) { 115 | styles.push({ 116 | "style": { 117 | "content": "\"" + content.replace(/"/g, "\\22 ") + "\"", 118 | }, 119 | "selectors": _.map(scopeSelectorsByCss, (scopes, css) => { return { "css": css + "::before", "scopes": scopes }}) 120 | }) 121 | } 122 | 123 | return styles 124 | }) 125 | 126 | var output = header(theme) 127 | rules.map(rule => { 128 | if (Object.keys(rule.style).length != 0) { 129 | output += rule.selectors.map( selector => { 130 | return selector.css + " /* " + selector.scopes.join(", ") + " */" 131 | }).join(",\n") 132 | output += " {\n" 133 | output += _.map(rule.style, (v, k) => { return " " + k + ": " + v + ";" }).join("\n") 134 | output += "\n}\n\n" 135 | } 136 | }) 137 | mkdirp.sync("build/css") 138 | fs.writeFileSync("build/css/" + theme.filename + ".map.json", JSON.stringify(classesByScope)) 139 | fs.writeFileSync("build/css/" + theme.filename + ".css", output) 140 | } 141 | -------------------------------------------------------------------------------- /lib/adapters/index.js: -------------------------------------------------------------------------------- 1 | const css = require("./css") 2 | const tmtheme = require("./tmtheme") 3 | const atom = require("./atom") 4 | const codemirror = require("./codemirror") 5 | const vscode = require("./vscode") 6 | 7 | module.exports = { 8 | "css": css, 9 | "tmtheme": tmtheme, 10 | "codemirror": codemirror, 11 | "atom": atom, 12 | "vscode": vscode 13 | } 14 | -------------------------------------------------------------------------------- /lib/adapters/tmtheme.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const plist = require("plist") 3 | const _ = require("lodash") 4 | const mkdirp = require("mkdirp") 5 | 6 | module.exports = (theme) => { 7 | var output = plist.build(theme) 8 | var dir = "build/tmtheme/" + theme.name + ".tmbundle/Themes/" 9 | mkdirp.sync(dir) 10 | fs.writeFileSync(dir + theme.name + ".tmTheme", output) 11 | } 12 | -------------------------------------------------------------------------------- /lib/adapters/vscode.js: -------------------------------------------------------------------------------- 1 | const mkdirp = require("mkdirp") 2 | const fs = require("fs") 3 | 4 | const mappings = { 5 | "background": ["editor.background"], 6 | "foreground": ["editor.foreground"], 7 | "hoverHighlight": ["editor.hoverHighlightBackground"], 8 | "linkForeground": ["editorLink.foreground"], 9 | "selection": ["editor.selectionBackground"], 10 | "inactiveSelection": ["editor.inactiveSelectionBackground"], 11 | "selectionHighlightColor": ["editor.selectionHighlightBackground"], 12 | "wordHighlight": ["editor.wordHighlightBackground"], 13 | "wordHighlightStrong": ["editor.wordHighlightStrongBackground"], 14 | "findMatchHighlight": ["editor.findMatchHighlightBackground", "peekViewResult.matchHighlightBackground"], 15 | "currentFindMatchHighlight": ["editor.findMatchBackground"], 16 | "findRangeHighlight": ["editor.findRangeHighlightBackground"], 17 | "referenceHighlight": ["peekViewEditor.matchHighlightBackground"], 18 | "lineHighlight": ["editor.lineHighlightBackground"], 19 | "rangeHighlight": ["editor.rangeHighlightBackground"], 20 | "caret": ["editorCursor.foreground"], 21 | "invisibles": ["editorWhitespace.foreground"], 22 | "guide": ["editorIndentGuide.background"], 23 | "ansiBlack": ["terminal.ansiBlack"], 24 | "ansiRed": ["terminal.ansiRed"], 25 | "ansiGreen": ["terminal.ansiGreen"], 26 | "ansiYellow": ["terminal.ansiYellow"], 27 | "ansiBlue": ["terminal.ansiBlue"], 28 | "ansiMagenta": ["terminal.ansiMagenta"], 29 | "ansiCyan": ["terminal.ansiCyan"], 30 | "ansiWhite": ["terminal.ansiWhite"], 31 | "ansiBrightBlack": ["terminal.ansiBrightBlack"], 32 | "ansiBrightRed": ["terminal.ansiBrightRed"], 33 | "ansiBrightGreen": ["terminal.ansiBrightGreen"], 34 | "ansiBrightYellow": ["terminal.ansiBrightYellow"], 35 | "ansiBrightBlue": ["terminal.ansiBrightBlue"], 36 | "ansiBrightMagenta": ["terminal.ansiBrightMagenta"], 37 | "ansiBrightCyan": ["terminal.ansiBrightCyan"], 38 | "ansiBrightWhite": ["terminal.ansiBrightWhite"] 39 | } 40 | 41 | module.exports = (theme) => { 42 | mkdirp.sync(`build/vscode/${theme.filename}`) 43 | 44 | const vstheme = { 45 | tokenColors: [] 46 | } 47 | 48 | let themeSettings = null; 49 | 50 | theme.settings.forEach((setting) => { 51 | const settings = setting.settings 52 | const scope = setting.scope 53 | 54 | if (!themeSettings && settings) { 55 | themeSettings = settings 56 | } 57 | 58 | if (!scope) { 59 | vstheme.tokenColors.push(setting) 60 | } else { 61 | const scopes = setting.scope.split(',').map(s => s.trim()) 62 | const data = { 63 | scope: scopes.length > 1 ? scopes : scopes.toString(), 64 | settings: settings 65 | } 66 | if (setting.name) { 67 | data.name = setting.name 68 | } 69 | vstheme.tokenColors.push(data) 70 | } 71 | }) 72 | 73 | if (themeSettings) { 74 | vstheme.colors = {} 75 | for (let k in mappings) { 76 | const v = mappings[k] 77 | const themeColor = themeSettings[k] 78 | if (v && v.length && themeColor) { 79 | v.forEach(n => { 80 | vstheme.colors[n] = themeColor 81 | }) 82 | } 83 | } 84 | } 85 | 86 | 87 | vstheme.name = theme.name 88 | 89 | fs.writeFileSync(`./build/vscode/${theme.filename}/${theme.name}.json`, JSON.stringify(vstheme, null, '\t')) 90 | } 91 | -------------------------------------------------------------------------------- /lib/templates/atom/editor.less: -------------------------------------------------------------------------------- 1 | atom-text-editor { 2 | background-color: @syntax-background-color; 3 | color: @syntax-text-color; 4 | 5 | .line.cursor-line { 6 | background-color: @syntax-cursor-line; 7 | } 8 | 9 | .invisible { 10 | color: @syntax-invisible-color; 11 | } 12 | 13 | .cursor { 14 | border-left: 2px solid @syntax-cursor-color; 15 | } 16 | 17 | .selection .region { 18 | background-color: @syntax-selection-color; 19 | } 20 | 21 | .bracket-matcher .region { 22 | border-bottom: 1px solid @syntax-cursor-color; 23 | box-sizing: border-box; 24 | z-index: 1; 25 | } 26 | 27 | .invisible-character { 28 | color: @syntax-invisible-character-color; 29 | } 30 | 31 | .indent-guide { 32 | color: @syntax-indent-guide-color; 33 | } 34 | 35 | .wrap-guide { 36 | background-color: @syntax-wrap-guide-color; 37 | } 38 | 39 | .gutter { 40 | background-color: @syntax-gutter-background-color; 41 | color: @syntax-gutter-text-color; 42 | 43 | .line-number { 44 | color: @syntax-gutter-text-color; 45 | -webkit-font-smoothing: antialiased; 46 | 47 | &.cursor-line { 48 | color: @syntax-gutter-text-color-selected; 49 | background-color: @syntax-gutter-background-color-selected; 50 | } 51 | 52 | .icon-right { 53 | color: @syntax-text-color; 54 | } 55 | } 56 | 57 | &:not(.git-diff-icon) .line-number.git-line-removed { 58 | &.git-line-removed::before { 59 | bottom: -3px; 60 | } 61 | &::after { 62 | content: ""; 63 | position: absolute; 64 | left: 0px; 65 | bottom: 0px; 66 | width: 25px; 67 | border-bottom: 1px dotted fade(@syntax-color-removed, 50%); 68 | pointer-events: none; 69 | } 70 | } 71 | } 72 | 73 | .gutter .line-number.folded, 74 | .gutter .line-number:after, 75 | .fold-marker:after { 76 | color: @syntax-gutter-text-color-selected; 77 | } 78 | } 79 | 80 | atom-text-editor .search-results .syntax--marker .region { 81 | background-color: transparent; 82 | border: 1px solid @syntax-result-marker-color; 83 | } 84 | 85 | atom-text-editor .search-results .syntax--marker.current-result .region { 86 | border: 1px solid @syntax-result-marker-color-selected; 87 | } 88 | -------------------------------------------------------------------------------- /lib/templates/atom/syntax-variables.less: -------------------------------------------------------------------------------- 1 | // This defines all syntax variables that syntax themes must implement when they 2 | // include a syntax-variables.less file. 3 | 4 | // General colors 5 | @syntax-text-color: ${foreground}; 6 | @syntax-cursor-color: ${caret}; 7 | @syntax-selection-color: ${selection}; 8 | @syntax-background-color: ${background}; 9 | @syntax-cursor-line: ${lineHighlight}; 10 | @syntax-invisible-color: ${invisibles}; 11 | 12 | // Guide colors 13 | @syntax-wrap-guide-color: ${guide}; 14 | @syntax-indent-guide-color: ${guide}; 15 | @syntax-invisible-character-color: ${invisibles}; 16 | 17 | // For find and replace markers 18 | @syntax-result-marker-color: ${findHighlight}; 19 | @syntax-result-marker-color-selected: ${findHighlightForeground}; 20 | 21 | // Gutter colors 22 | @syntax-gutter-text-color: ${gutterForeground}; 23 | @syntax-gutter-text-color-selected: ${foreground}; 24 | @syntax-gutter-background-color: ${background}; 25 | @syntax-gutter-background-color-selected: ${lineHighlight}; 26 | 27 | // For git diff info. i.e. in the gutter 28 | @syntax-color-renamed: ${diffRenamed}; 29 | @syntax-color-added: ${diffAdded}; 30 | @syntax-color-modified: ${diffModified}; 31 | @syntax-color-removed: ${diffDeleted}; 32 | -------------------------------------------------------------------------------- /lib/templates/codemirror.scss: -------------------------------------------------------------------------------- 1 | @import "primer-support/index.scss"; 2 | 3 | .cm-s-${theme} { 4 | 5 | &.CodeMirror { 6 | background: ${background}; 7 | color: ${foreground}; 8 | } 9 | 10 | .CodeMirror-gutters { 11 | background: ${background}; 12 | border-right-width: 0; 13 | } 14 | 15 | .CodeMirror-guttermarker { 16 | color: white; 17 | } 18 | 19 | .CodeMirror-guttermarker-subtle { 20 | color: #d0d0d0; 21 | } 22 | 23 | .CodeMirror-linenumber { 24 | color: ${invisibles}; 25 | padding: 0 $spacer-3 0 $spacer-3; 26 | } 27 | 28 | .CodeMirror-cursor { 29 | border-left: 1px solid ${foreground}; 30 | } 31 | 32 | div.CodeMirror-selected, 33 | .CodeMirror-line::selection, 34 | .CodeMirror-line > span::selection, 35 | .CodeMirror-line > span > span::selection, 36 | .CodeMirror-line::-moz-selection, 37 | .CodeMirror-line > span::-moz-selection, 38 | .CodeMirror-line > span > span::-moz-selection { 39 | background: ${selection}; 40 | } 41 | 42 | .CodeMirror-activeline-background { 43 | background: ${lineHighlight}; 44 | } 45 | 46 | .CodeMirror-matchingbracket { 47 | text-decoration: underline; 48 | color: ${foreground} !important; 49 | } 50 | 51 | .CodeMirror-lines { 52 | font-family: $mono-font; 53 | font-size: $h6-size; 54 | background: ${background}; 55 | line-height: $lh-default; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/themes/dark.json: -------------------------------------------------------------------------------- 1 | { 2 | "author" : "GitHub", 3 | "settings" : [ 4 | { 5 | "settings" : { 6 | "background" : "#24292e", 7 | "foreground" : "#f6f8fa", 8 | "lineHighlight": "#444d56", 9 | "invisibles" : "#6a737d", 10 | "selection": "#4c2889", 11 | "caret": "#fff", 12 | "diffRenamed": "#fafbfc", 13 | "diffModified": "#f9c513", 14 | "diffDeleted": "#d73a49", 15 | "diffAdded": "#34d058", 16 | "inactiveSelection" : "#444d56", 17 | "selectionBorder" : "#444d56", 18 | "findHighlight" : "#fb8532", 19 | "findHighlightForeground" : "#24292e", 20 | "guide" : "#6a737d", 21 | "activeGuide" : "#f6f8fa", 22 | "stackGuide" : "#959da5", 23 | "highlight" : "#f6f8fa", 24 | "popupCss" : "", 25 | "highlightForeground" : "#f6f8fa", 26 | "tagsOptions" : "underline", 27 | "bracketContentsOptions" : "underline", 28 | "bracketContentsForeground" : "#e1e4e8", 29 | "bracketsOptions" : "underline", 30 | "bracketsForeground" : "#e1e4e8", 31 | "gutterForeground" : "#f6f8fa" 32 | } 33 | }, 34 | { 35 | "scope" : "comment, punctuation.definition.comment, string.comment", 36 | "settings" : { 37 | "foreground" : "#959da5" 38 | }, 39 | "name" : "Comment" 40 | }, 41 | { 42 | "scope" : "constant, entity.name.constant, variable.other.constant, variable.language", 43 | "settings" : { 44 | "foreground" : "#c8e1ff" 45 | }, 46 | "name" : "Constant" 47 | }, 48 | { 49 | "scope" : "keyword.operator.symbole, keyword.other.mark", 50 | "name": "Clojure workaround; don't highlight these separately from their enclosing scope", 51 | "settings": {} 52 | }, 53 | { 54 | "scope" : "entity, entity.name", 55 | "settings" : { 56 | "fontStyle" : "", 57 | "foreground" : "#b392f0" 58 | }, 59 | "name" : "Entity" 60 | }, 61 | { 62 | "scope": "variable.parameter.function", 63 | "settings" : { 64 | "foreground" : "#f6f8fa" 65 | } 66 | }, 67 | { 68 | "scope": "entity.name.tag", 69 | "settings" : { 70 | "fontStyle" : "", 71 | "foreground" : "#7bcc72" 72 | } 73 | }, 74 | { 75 | "scope" : "keyword", 76 | "settings" : { 77 | "fontStyle" : "", 78 | "foreground" : "#ea4a5a" 79 | }, 80 | "name" : "Keyword" 81 | }, 82 | { 83 | "scope" : "storage, storage.type", 84 | "settings" : { 85 | "foreground" : "#ea4a5a" 86 | }, 87 | "name" : "Storage" 88 | }, 89 | { 90 | "scope": "storage.modifier.package, storage.modifier.import, storage.type.java", 91 | "settings" : { 92 | "foreground" : "#f6f8fa" 93 | } 94 | }, 95 | { 96 | "scope" : "string, punctuation.definition.string, string punctuation.section.embedded source", 97 | "settings" : { 98 | "fontStyle" : "", 99 | "foreground" : "#79b8ff" 100 | }, 101 | "name" : "String" 102 | }, 103 | { 104 | "name": "Ada workaround; don't highlight imports as strings", 105 | "scope": "string.unquoted.import.ada", 106 | "settings": {} 107 | }, 108 | { 109 | "scope" : "support", 110 | "settings" : { 111 | "fontStyle" : "", 112 | "foreground" : "#c8e1ff" 113 | }, 114 | "name" : "Support" 115 | }, 116 | { 117 | "scope": "meta.property-name", 118 | "settings" : { 119 | "fontStyle" : "", 120 | "foreground" : "#c8e1ff" 121 | } 122 | }, 123 | { 124 | "scope" : "variable", 125 | "settings" : { 126 | "fontStyle" : "", 127 | "foreground" : "#fb8532" 128 | }, 129 | "name" : "Variable" 130 | }, 131 | { 132 | "scope": "variable.other", 133 | "settings" : { 134 | "foreground" : "#f6f8fa" 135 | } 136 | }, 137 | { 138 | "scope" : "invalid.broken", 139 | "settings" : { 140 | "fontStyle" : "bold italic underline", 141 | "foreground" : "#d73a49" 142 | }, 143 | "name" : "Invalid - Broken" 144 | }, 145 | { 146 | "scope" : "invalid.deprecated", 147 | "settings" : { 148 | "fontStyle" : "bold italic underline", 149 | "foreground" : "#d73a49" 150 | }, 151 | "name" : "Invalid – Deprecated" 152 | }, 153 | { 154 | "scope" : "invalid.illegal", 155 | "settings" : { 156 | "fontStyle" : "italic underline", 157 | "foreground" : "#fafbfc", 158 | "background" : "#d73a49" 159 | }, 160 | "name" : "Invalid – Illegal" 161 | }, 162 | { 163 | "scope" : "carriage-return", 164 | "settings" : { 165 | "fontStyle" : "italic underline", 166 | "foreground" : "#fafbfc", 167 | "background" : "#d73a49", 168 | "content": "^M" 169 | }, 170 | "name" : "Carriage Return" 171 | }, 172 | { 173 | "scope" : "invalid.unimplemented", 174 | "settings" : { 175 | "fontStyle" : "bold italic underline", 176 | "foreground" : "#d73a49" 177 | }, 178 | "name" : "Invalid - Unimplemented" 179 | }, 180 | { 181 | "scope" : "message.error", 182 | "settings" : { 183 | "foreground" : "#d73a49" 184 | } 185 | }, 186 | { 187 | "scope" : "string source", 188 | "settings" : { 189 | "fontStyle" : "", 190 | "foreground" : "#f6f8fa" 191 | }, 192 | "name" : "String embedded-source" 193 | }, 194 | { 195 | "scope" : "string variable", 196 | "settings" : { 197 | "fontStyle" : "", 198 | "foreground" : "#c8e1ff" 199 | }, 200 | "name" : "String variable" 201 | }, 202 | { 203 | "scope" : "source.regexp, string.regexp", 204 | "settings" : { 205 | "fontStyle" : "", 206 | "foreground" : "#79b8ff" 207 | }, 208 | "name" : "String.regexp" 209 | }, 210 | { 211 | "scope" : "string.regexp.character-class, string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition", 212 | "settings" : { 213 | "foreground" : "#79b8ff" 214 | }, 215 | "name" : "String.regexp.«special»" 216 | }, 217 | { 218 | "scope" : "string.regexp constant.character.escape", 219 | "settings" : { 220 | "fontStyle" : "bold", 221 | "foreground" : "#7bcc72" 222 | }, 223 | "name" : "String.regexp constant.character.escape" 224 | }, 225 | { 226 | "scope" : "support.constant", 227 | "settings" : { 228 | "fontStyle" : "", 229 | "foreground" : "#c8e1ff" 230 | }, 231 | "name" : "Support.constant" 232 | }, 233 | { 234 | "scope" : "support.variable", 235 | "settings" : { 236 | "foreground" : "#c8e1ff" 237 | }, 238 | "name" : "Support.variable" 239 | }, 240 | { 241 | "scope": "meta.module-reference", 242 | "settings" : { 243 | "foreground" : "#c8e1ff" 244 | }, 245 | "name": "meta module-reference" 246 | }, 247 | { 248 | "scope" : "markup.list", 249 | "settings" : { 250 | "foreground" : "#fb8532" 251 | }, 252 | "name" : "Markup.list" 253 | }, 254 | { 255 | "scope" : "markup.heading, markup.heading entity.name", 256 | "settings" : { 257 | "fontStyle" : "bold", 258 | "foreground" : "#0366d6" 259 | }, 260 | "name" : "Markup.heading" 261 | }, 262 | { 263 | "scope" : "markup.quote", 264 | "settings" : { 265 | "foreground" : "#c8e1ff" 266 | }, 267 | "name" : "Markup.quote" 268 | }, 269 | { 270 | "scope" : "markup.italic", 271 | "settings" : { 272 | "fontStyle" : "italic", 273 | "foreground" : "#f6f8fa" 274 | }, 275 | "name" : "Markup.italic" 276 | }, 277 | { 278 | "scope" : "markup.bold", 279 | "settings" : { 280 | "fontStyle" : "bold", 281 | "foreground" : "#f6f8fa" 282 | }, 283 | "name" : "Markup.bold" 284 | }, 285 | { 286 | "scope" : "markup.raw", 287 | "settings" : { 288 | "fontStyle" : "", 289 | "foreground" : "#c8e1ff" 290 | }, 291 | "name" : "Markup.raw" 292 | }, 293 | { 294 | "scope" : "markup.deleted, meta.diff.header.from-file, punctuation.definition.deleted", 295 | "settings" : { 296 | "background": "#ffeef0", 297 | "foreground" : "#b31d28" 298 | }, 299 | "name" : "Markup.deleted" 300 | }, 301 | { 302 | "scope": "markup.inserted, meta.diff.header.to-file, punctuation.definition.inserted", 303 | "settings" : { 304 | "background": "#f0fff4", 305 | "foreground" : "#176f2c" 306 | }, 307 | "name" : "Markup.inserted" 308 | }, 309 | { 310 | "scope" : "markup.changed, punctuation.definition.changed", 311 | "settings" : { 312 | "background" : "#fffdef", 313 | "foreground" : "#b08800" 314 | } 315 | }, 316 | { 317 | "scope" : "markup.ignored, markup.untracked", 318 | "settings" : { 319 | "foreground" : "#2f363d", 320 | "background" : "#959da5" 321 | } 322 | }, 323 | { 324 | "scope": "meta.diff.range", 325 | "settings" : { 326 | "fontStyle": "bold", 327 | "foreground" : "#b392f0" 328 | } 329 | }, 330 | { 331 | "scope": "meta.diff.header", 332 | "settings" : { 333 | "foreground" : "#c8e1ff" 334 | } 335 | }, 336 | { 337 | "scope" : "meta.separator", 338 | "settings" : { 339 | "fontStyle" : "bold", 340 | "foreground": "#0366d6" 341 | }, 342 | "name" : "Meta.separator" 343 | }, 344 | { 345 | "name": "Output", 346 | "scope": "meta.output", 347 | "settings" : { 348 | "foreground": "#0366d6" 349 | } 350 | }, 351 | { 352 | "scope" : "brackethighlighter.tag, brackethighlighter.curly, brackethighlighter.round, brackethighlighter.square, brackethighlighter.angle, brackethighlighter.quote", 353 | "settings" : { 354 | "foreground" : "#ffeef0" 355 | } 356 | }, 357 | { 358 | "scope" : "brackethighlighter.unmatched", 359 | "settings" : { 360 | "foreground" : "#d73a49" 361 | } 362 | }, 363 | { 364 | "scope" : "sublimelinter.mark.error", 365 | "settings" : { 366 | "foreground" : "#d73a49" 367 | } 368 | }, 369 | { 370 | "scope" : "sublimelinter.mark.warning", 371 | "settings" : { 372 | "foreground" : "#fb8532" 373 | } 374 | }, 375 | { 376 | "scope" : "sublimelinter.gutter-mark", 377 | "settings" : { 378 | "foreground" : "#6a737d" 379 | } 380 | }, 381 | { 382 | "scope" : "constant.other.reference.link, string.other.link", 383 | "settings" : { 384 | "foreground" : "#79b8ff", 385 | "fontStyle" : "underline" 386 | } 387 | } 388 | ], 389 | "comment" : "GitHub Dark syntax theme", 390 | "name" : "GitHub Dark", 391 | "semanticClass" : "theme.dark.github", 392 | "filename": "github-dark", 393 | "uuid": "C8E24EAE-6212-41E3-AC1A-F49362B6150D" 394 | } 395 | -------------------------------------------------------------------------------- /lib/themes/index.js: -------------------------------------------------------------------------------- 1 | const dark = require("./dark") 2 | const light = require("./light") 3 | 4 | module.exports = [ 5 | dark, 6 | light 7 | ] 8 | -------------------------------------------------------------------------------- /lib/themes/light.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "GitHub", 3 | "settings": [ 4 | { 5 | "settings": { 6 | "selection": "#c8c8fa", 7 | "lineHighlight": "#fafbfc", 8 | "background": "#fff", 9 | "foreground": "#24292e", 10 | "invisibles": "#959da5", 11 | "caret": "#24292e", 12 | "diffRenamed": "#fafbfc", 13 | "diffModified": "#f9c513", 14 | "diffDeleted": "#d73a49", 15 | "diffAdded": "#34d058", 16 | "markdown": "#f7f7f7", 17 | "inactiveSelection": "#fafbfc", 18 | "selectionBorder": "#fafbfc", 19 | "findHighlight": "#e36209", 20 | "findHighlightForeground": "#fff8f2", 21 | "guide": "#959da5", 22 | "activeGuide": "#24292e", 23 | "stackGuide": "#959da5", 24 | "highlight": "#444d56", 25 | "popupCss": "", 26 | "highlightForeground": "#444d56", 27 | "tagsOptions": "underline", 28 | "bracketContentsOptions": "underline", 29 | "bracketContentsForeground": "#24292e", 30 | "bracketsOptions": "underline", 31 | "bracketsForeground": "#24292e", 32 | "gutterForeground": "#24292e" 33 | } 34 | }, 35 | { 36 | "scope": "comment, punctuation.definition.comment, string.comment", 37 | "settings": { 38 | "foreground": "#6a737d" 39 | }, 40 | "name": "Comment" 41 | }, 42 | { 43 | "scope": "constant, entity.name.constant, variable.other.constant, variable.language", 44 | "settings": { 45 | "foreground": "#005cc5" 46 | }, 47 | "name": "Constant" 48 | }, 49 | { 50 | "scope": "keyword.operator.symbole, keyword.other.mark", 51 | "name": "Clojure workaround; don't highlight these separately from their enclosing scope", 52 | "settings": {} 53 | }, 54 | { 55 | "scope": "entity, entity.name", 56 | "settings": { 57 | "fontStyle": "", 58 | "foreground": "#6f42c1" 59 | }, 60 | "name": "Entity" 61 | }, 62 | { 63 | "scope": "variable.parameter.function", 64 | "settings": { 65 | "foreground": "#24292e" 66 | } 67 | }, 68 | { 69 | "scope": "entity.name.tag", 70 | "settings": { 71 | "fontStyle": "", 72 | "foreground": "#22863a" 73 | } 74 | }, 75 | { 76 | "scope": "keyword", 77 | "settings": { 78 | "fontStyle": "", 79 | "foreground": "#d73a49" 80 | }, 81 | "name": "Keyword" 82 | }, 83 | { 84 | "scope": "storage, storage.type", 85 | "settings": { 86 | "foreground": "#d73a49" 87 | }, 88 | "name": "Storage" 89 | }, 90 | { 91 | "scope": "storage.modifier.package, storage.modifier.import, storage.type.java", 92 | "settings": { 93 | "foreground": "#24292e" 94 | } 95 | }, 96 | { 97 | "scope": "string, punctuation.definition.string, string punctuation.section.embedded source", 98 | "settings": { 99 | "fontStyle": "", 100 | "foreground": "#032f62" 101 | }, 102 | "name": "String" 103 | }, 104 | { 105 | "name": "Ada workaround; don't highlight imports as strings", 106 | "scope": "string.unquoted.import.ada", 107 | "settings": {} 108 | }, 109 | { 110 | "scope": "support", 111 | "settings": { 112 | "fontStyle": "", 113 | "foreground": "#005cc5" 114 | }, 115 | "name": "Support" 116 | }, 117 | { 118 | "scope": "meta.property-name", 119 | "settings": { 120 | "fontStyle": "", 121 | "foreground": "#005cc5" 122 | } 123 | }, 124 | { 125 | "scope": "variable", 126 | "settings": { 127 | "fontStyle": "", 128 | "foreground": "#e36209" 129 | }, 130 | "name": "Variable" 131 | }, 132 | { 133 | "scope": "variable.other", 134 | "settings": { 135 | "foreground": "#24292e" 136 | } 137 | }, 138 | { 139 | "scope": "invalid.broken", 140 | "settings": { 141 | "fontStyle": "bold italic underline", 142 | "foreground": "#b31d28" 143 | }, 144 | "name": "Invalid - Broken" 145 | }, 146 | { 147 | "scope": "invalid.deprecated", 148 | "settings": { 149 | "fontStyle": "bold italic underline", 150 | "foreground": "#b31d28" 151 | }, 152 | "name": "Invalid – Deprecated" 153 | }, 154 | { 155 | "scope": "invalid.illegal", 156 | "settings": { 157 | "fontStyle": "italic underline", 158 | "background": "#b31d28", 159 | "foreground": "#fafbfc" 160 | }, 161 | "name": "Invalid – Illegal" 162 | }, 163 | { 164 | "scope": "carriage-return", 165 | "settings": { 166 | "fontStyle": "italic underline", 167 | "background": "#d73a49", 168 | "foreground": "#fafbfc", 169 | "content": "^M" 170 | }, 171 | "name": "Carriage Return" 172 | }, 173 | { 174 | "scope": "invalid.unimplemented", 175 | "settings": { 176 | "fontStyle": "bold italic underline", 177 | "foreground": "#b31d28" 178 | }, 179 | "name": "Invalid - Unimplemented" 180 | }, 181 | { 182 | "scope": "message.error", 183 | "settings": { 184 | "foreground": "#b31d28" 185 | } 186 | }, 187 | { 188 | "scope": "string source", 189 | "settings": { 190 | "fontStyle": "", 191 | "foreground": "#24292e" 192 | }, 193 | "name": "String embedded-source" 194 | }, 195 | { 196 | "scope": "string variable", 197 | "settings": { 198 | "fontStyle": "", 199 | "foreground": "#005cc5" 200 | }, 201 | "name": "String variable" 202 | }, 203 | { 204 | "scope": "source.regexp, string.regexp", 205 | "settings": { 206 | "fontStyle": "", 207 | "foreground": "#032f62" 208 | }, 209 | "name": "String.regexp" 210 | }, 211 | { 212 | "scope": "string.regexp.character-class, string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition", 213 | "settings": { 214 | "foreground": "#032f62" 215 | }, 216 | "name": "String.regexp.«special»" 217 | }, 218 | { 219 | "scope": "string.regexp constant.character.escape", 220 | "settings": { 221 | "fontStyle": "bold", 222 | "foreground": "#22863a" 223 | }, 224 | "name": "String.regexp constant.character.escape" 225 | }, 226 | { 227 | "scope": "support.constant", 228 | "settings": { 229 | "fontStyle": "", 230 | "foreground": "#005cc5" 231 | }, 232 | "name": "Support.constant" 233 | }, 234 | { 235 | "scope": "support.variable", 236 | "settings": { 237 | "foreground": "#005cc5" 238 | }, 239 | "name": "Support.variable" 240 | }, 241 | { 242 | "scope": "meta.module-reference", 243 | "settings": { 244 | "foreground": "#005cc5" 245 | }, 246 | "name": "meta module-reference" 247 | }, 248 | { 249 | "scope": "markup.list", 250 | "settings": { 251 | "foreground": "#735c0f" 252 | }, 253 | "name": "Markup.list" 254 | }, 255 | { 256 | "scope": "markup.heading, markup.heading entity.name", 257 | "settings": { 258 | "fontStyle": "bold", 259 | "foreground": "#005cc5" 260 | }, 261 | "name": "Markup.heading" 262 | }, 263 | { 264 | "scope": "markup.quote", 265 | "settings": { 266 | "foreground": "#22863a" 267 | }, 268 | "name": "Markup.quote" 269 | }, 270 | { 271 | "scope": "markup.italic", 272 | "settings": { 273 | "fontStyle": "italic", 274 | "foreground": "#24292e" 275 | }, 276 | "name": "Markup.italic" 277 | }, 278 | { 279 | "scope": "markup.bold", 280 | "settings": { 281 | "fontStyle": "bold", 282 | "foreground": "#24292e" 283 | }, 284 | "name": "Markup.bold" 285 | }, 286 | { 287 | "scope": "markup.raw", 288 | "settings": { 289 | "fontStyle": "", 290 | "foreground": "#005cc5" 291 | }, 292 | "name": "Markup.raw" 293 | }, 294 | { 295 | "scope": "markup.deleted, meta.diff.header.from-file, punctuation.definition.deleted", 296 | "settings": { 297 | "background": "#ffeef0", 298 | "foreground": "#b31d28" 299 | }, 300 | "name": "Markup.deleted" 301 | }, 302 | { 303 | "scope": "markup.inserted, meta.diff.header.to-file, punctuation.definition.inserted", 304 | "settings": { 305 | "background": "#f0fff4", 306 | "foreground": "#22863a" 307 | }, 308 | "name": "Markup.inserted" 309 | }, 310 | { 311 | "scope": "markup.changed, punctuation.definition.changed", 312 | "settings": { 313 | "background": "#ffebda", 314 | "foreground": "#e36209" 315 | } 316 | }, 317 | { 318 | "scope": "markup.ignored, markup.untracked", 319 | "settings": { 320 | "foreground": "#f6f8fa", 321 | "background": "#005cc5" 322 | } 323 | }, 324 | { 325 | "scope": "meta.diff.range", 326 | "settings": { 327 | "foreground": "#6f42c1", 328 | "fontStyle": "bold" 329 | } 330 | }, 331 | { 332 | "scope": "meta.diff.header", 333 | "settings": { 334 | "foreground": "#005cc5" 335 | } 336 | }, 337 | { 338 | "scope": "meta.separator", 339 | "settings": { 340 | "fontStyle": "bold", 341 | "foreground": "#005cc5" 342 | }, 343 | "name": "Meta.separator" 344 | }, 345 | { 346 | "name": "Output", 347 | "scope": "meta.output", 348 | "settings": { 349 | "foreground": "#005cc5" 350 | } 351 | }, 352 | { 353 | "scope" : "brackethighlighter.tag, brackethighlighter.curly, brackethighlighter.round, brackethighlighter.square, brackethighlighter.angle, brackethighlighter.quote", 354 | "settings" : { 355 | "foreground" : "#586069" 356 | } 357 | }, 358 | { 359 | "scope" : "brackethighlighter.unmatched", 360 | "settings" : { 361 | "foreground" : "#b31d28" 362 | } 363 | }, 364 | { 365 | "scope" : "sublimelinter.mark.error", 366 | "settings" : { 367 | "foreground" : "#b31d28" 368 | } 369 | }, 370 | { 371 | "scope" : "sublimelinter.mark.warning", 372 | "settings" : { 373 | "foreground" : "#e36209" 374 | } 375 | }, 376 | { 377 | "scope" : "sublimelinter.gutter-mark", 378 | "settings" : { 379 | "foreground" : "#959da5" 380 | } 381 | }, 382 | { 383 | "scope" : "constant.other.reference.link, string.other.link", 384 | "settings" : { 385 | "foreground" : "#032f62", 386 | "fontStyle" : "underline" 387 | } 388 | } 389 | ], 390 | "comment": "GitHub Light syntax theme", 391 | "name": "GitHub Light", 392 | "semanticClass": "theme.light.github", 393 | "filename": "github-light", 394 | "uuid": "A1C4DFA0-7031-11E4-9803-0800200C9A66" 395 | } 396 | -------------------------------------------------------------------------------- /lib/utils/index.js: -------------------------------------------------------------------------------- 1 | const package = require("../../package.json") 2 | 3 | module.exports.header = (theme) => { 4 | return `/*! 5 | * ${theme.name} v${package.version} 6 | * Copyright (c) 2012 - ${new Date().getFullYear()} ${package.author} 7 | * Licensed under MIT (https://github.com/primer/github-syntax-theme-generator/blob/master/LICENSE) 8 | */\n\n` 9 | } 10 | 11 | module.exports.property = (key) => { 12 | const map = { 13 | "foreground": "color", 14 | "background": "background-color", 15 | "bold": "font-weight", 16 | "italic": "font-style", 17 | "underline": "text-decoration" 18 | } 19 | 20 | return map[key] 21 | } 22 | 23 | module.exports.declarations = (settings) => { 24 | let declarations = "" 25 | Object.keys(settings).forEach((key) => { 26 | if (key === "fontStyle") { 27 | const value = settings[key] 28 | if (value.trim() === "") { 29 | declarations += "\n font-weight: normal;\n font-style: normal;\n text-decoration: none;" 30 | } else { 31 | value.split(" ").forEach((val) => { 32 | declarations += `\n ${module.exports.property(val)}: ${val};` 33 | }) 34 | } 35 | } else { 36 | declarations += `\n ${module.exports.property(key)}: ${settings[key]};` 37 | } 38 | }) 39 | return declarations 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.5.0", 3 | "name": "github-syntax-theme-generator", 4 | "description": "The GitHub syntax theme generator will generate themes for multiple platforms based on the GitHub syntax theme.", 5 | "homepage": "https://github.com/primer/github-syntax-theme-generator", 6 | "author": "GitHub, Inc.", 7 | "license": "MIT", 8 | "main": "index.js", 9 | "files": [ 10 | "index.js", 11 | "lib", 12 | "build" 13 | ], 14 | "repository": "https://github.com/primer/github-syntax-theme-generator.git", 15 | "bugs": { 16 | "url": "https://github.com/primer/github-syntax-theme-generator/issues" 17 | }, 18 | "scripts": { 19 | "build": "node index.js", 20 | "prepublish": "npm run build", 21 | "ava": "ava --verbose --fail-fast \"test/**/*.js\"", 22 | "lint": "eslint **/*.js", 23 | "test": "npm run lint && npm run build && npm run ava" 24 | }, 25 | "devDependencies": { 26 | "ace": "git+https://github.com/ajaxorg/ace.git", 27 | "ava": "^0.18.1", 28 | "colorable": "^1.0.5", 29 | "css-parse": "2.0.0", 30 | "css-stringify": "2.0.0", 31 | "eslint": "^3.14.1", 32 | "eslint-plugin-github": "^0.8.0", 33 | "lodash": "^4.16.6", 34 | "mkdirp": "^0.5.1", 35 | "node-sass": "^4.4.0", 36 | "plist": "^2.0.1", 37 | "primer-support": "^4.0.0" 38 | }, 39 | "keywords": [ 40 | "syntax", 41 | "github", 42 | "css", 43 | "theme", 44 | "code", 45 | "highlight", 46 | "generator" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /test/accessibility.js: -------------------------------------------------------------------------------- 1 | const test = require("ava") 2 | const colorable = require("colorable") 3 | const themes = require("../lib/themes") 4 | 5 | const foregrounds = ["foreground", "caret", "invisibles", "findHighlightForeground", "highlightForeground", "bracketContentsForeground", "bracketsForeground", "gutterForeground"] 6 | const ignore = ["selectionBorder", "guide", "activeGuide", "stackGuide"] 7 | 8 | function colorTest(background, foreground, message) { 9 | // Calculate contrast 10 | const result = colorable([foreground, background], { compact: true, threshold: 0 }).pop() 11 | if (result.combinations.length > 0) { 12 | 13 | // Get the combination 14 | const combinations = result.combinations.pop() 15 | // accessibility scores 16 | // const accessibility = combinations.accessibility 17 | 18 | // Test 19 | test(message, t => { 20 | t.truthy(combinations.contrast > 1, "Contrast is lower than 1; " + combinations.contrast) 21 | // t.truthy(accessibility.aa, "didn't pass aa critera. contrast: " + combinations.contrast ) 22 | // t.truthy(accessibility.aaLarge, "didn't pass aaLarge critera. contrast: " + combinations.contrast ) 23 | // t.truthy(accessibility.aaa, "didn't pass aaa critera. contrast: " + combinations.contrast ) 24 | // t.truthy(accessibility.aaaLarge, "didn't pass aaaLarge critera. contrast: " + combinations.contrast ) 25 | }) 26 | } 27 | } 28 | 29 | // For every theme 30 | themes.forEach(theme => { 31 | 32 | // Pull out the background colors 33 | const bgColors = theme.settings.filter(setting => { 34 | return !setting.scope 35 | }).pop() 36 | 37 | ignore.forEach(i => { 38 | delete bgColors.settings[i] 39 | }) 40 | 41 | const themeForegrounds = foregrounds.map(foreground => { 42 | return { 43 | "scope": foreground, 44 | "settings": { 45 | "foreground": bgColors.settings[foreground] 46 | }, 47 | "name": foreground 48 | } 49 | }) 50 | 51 | // For each setting 52 | theme.settings.concat(themeForegrounds).forEach(setting => { 53 | // make sure it's a scope setting 54 | if (setting.scope && setting.settings.foreground) { 55 | 56 | let foreground = setting.settings.foreground 57 | 58 | // If the scope has it's own background 59 | if (setting.settings.background) { 60 | // check against it's own background color 61 | colorTest(setting.settings.background, foreground, theme.name + ": " + setting.scope + " (" + foreground + ") on " + setting.settings.background + " background") 62 | foreground = setting.settings.background 63 | } 64 | 65 | // For each background color 66 | Object.keys(bgColors.settings).forEach(bg => { 67 | if (foregrounds.indexOf(bg) === -1) { 68 | // Get the background color 69 | const background = bgColors.settings[bg] 70 | if (background.indexOf("#") === 0) { 71 | colorTest(background, foreground, theme.name + ": " + setting.scope + " (" + foreground + ") on " + bg + " (" + background + ") background") 72 | } 73 | } 74 | }) 75 | } 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /test/utils/header.js: -------------------------------------------------------------------------------- 1 | const test = require("ava") 2 | const header = require("../../lib/utils/") 3 | const themes = require("../../lib/themes") 4 | const pkg = require("../../package.json") 5 | 6 | let darkThemeHeader = null 7 | 8 | test.before(() => { 9 | darkThemeHeader = header.header(themes[0]) 10 | }) 11 | 12 | test("license comment", t => { 13 | t.regex(darkThemeHeader, /\/\*!/, "Header is missing the license special comment /*!") 14 | }) 15 | 16 | test("theme name", t => { 17 | t.regex(darkThemeHeader, /GitHub Dark/) 18 | }) 19 | 20 | test("the current package version", t => { 21 | t.regex(darkThemeHeader, new RegExp(pkg.version)) 22 | }) 23 | 24 | test("correct year", t => { 25 | t.regex(darkThemeHeader, /2018/) 26 | }) 27 | 28 | test("package author", t => { 29 | t.regex(darkThemeHeader, new RegExp(pkg.author)) 30 | }) 31 | 32 | test("mentions the license", t => { 33 | t.regex(darkThemeHeader, /Licensed under MIT/) 34 | }) 35 | --------------------------------------------------------------------------------