Skip to content

Commit

Permalink
base version with CodeMirror
Browse files Browse the repository at this point in the history
  • Loading branch information
Farhad Ghayour committed Jan 22, 2015
1 parent e4e3948 commit 9c655e1
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 910 deletions.
Empty file added README.md
Empty file.
131 changes: 103 additions & 28 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ var fs = require('fs');
var path = require('path');
var plist = require('plist');
var CSSJSON = require('CSSJSON');
var supportedScopes = require('./supportedScopes');


/*******************************************************************************
* Current supported scopes between Sublime/TextMate and CodeMirror.
* Various references will not look the same, as CodeMirror
* and Sublime have different and limited ways of refering to the code syntax.
*/
var supportedScopes = require('./scopes/CodeMirrorSupportedScopes');


// The root JSON that gets parsed to CSS after populated.
var root = {};


/*******************************************************************************
* Parsying styles TODO????????
* Basic parsing of CSS styles provided by the XML format form Sublime.
*/
function parseStyles(styles) {
var css = [];
Expand All @@ -32,38 +42,67 @@ function parseStyles(styles) {
if (styles.background) {
css.push(['background', styles.background]);
}

return css;
}


/*******************************************************************************
* Write to the file
* Convert a given JSON to CSS and then display message after file has
* been written.
*/
function writeFile(styles) {
var data = CSSJSON.toCSS(styles);
fs.writeFile(__dirname + '/codemirror/famous.css', data, function(err) {
if(err) console.log(err);
function writeFile(json, themeName, outputDirectory, callback) {
var data = CSSJSON.toCSS(json);
var destination = [__dirname];

if (outputDirectory) {
destination.push(outputDirectory);
}

fs.writeFile(destination.join(''), data, function(err) {
if (err) console.log(err);
callback(themeName);
});
}


/*******************************************************************************
* Given a string, turn it into a CSS class.
*/
function convertClass(string) {
return '.' + string;
}


/*******************************************************************************
* A simple way of namespacing the entire CSS on top of CodeMirror's base styling.
* NOTE: The theme class is applied to the code editor via
* CodeMirror's API.
*/
function nameSpace(themeName) {
return convertClass('cm-s-' + themeName);
}


/*******************************************************************************
* Build a CSS selector with namespacing.
*/
function buildClass(themeName, selector) {
return [
nameSpace(themeName),
convertClass(selector)
].join(' ');
return [nameSpace(themeName), convertClass(selector)].join(' ');
}


/*******************************************************************************
* A helper function for printing our the entire root JSON.
*/
function print(json) {
console.log(JSON.stringify(json, null, 4));
}


/*******************************************************************************
* Constructs the root JSON with the necessary keys and information.
*/
function generateThemeInfo(themeInfo, theme) {
for(var themeInfo in theme) {
if (themeInfo.toLowerCase() !== 'settings') {
Expand All @@ -76,26 +115,42 @@ function generateThemeInfo(themeInfo, theme) {
root.unsupported = {};
}


/*******************************************************************************
* If a given scope is not yet supported, add it to the root's unsupported key.
*/
function addToUnsupported(scope, info) {
root.unsupported[scope] = info;
}


/*******************************************************************************
* Given the necessary information for the CSS values,
* write the information to the root JSON.
*/
function writeToRoot(selector, property, value) {
root.children[selector] = root.children[selector] || {};
root.children[selector].attributes = root.children[selector].attributes || {};
root.children[selector].attributes[property] = value;
}


/*******************************************************************************
* The global styles are a special treatment as they are formatted differently
* within Sublime's markup.
*/
function generateGlobalStyles(styles, themeName, theme) {
for(var scope in styles) {
var codeMirror = supportedScopes[scope];
if (codeMirror) {
var selector, property, value;
// Has extra information for a more complex selector
if (Array.isArray(codeMirror)) {
selector = buildClass(themeName, codeMirror[0]);
property = codeMirror[1];
value = styles[scope];
}
// The selector sits at the top of the theme
else {
selector = nameSpace(themeName),
property = codeMirror;
Expand All @@ -109,6 +164,11 @@ function generateGlobalStyles(styles, themeName, theme) {
}
}


/*******************************************************************************
* If the style's scope is supportted, write it to the root JSON.
* If not, add it to the unsupported key under the root JSON.
*/
function generateStyles(styles, themeName, theme) {
var codeMirror = supportedScopes[styles.scope];
if (codeMirror) {
Expand All @@ -125,8 +185,10 @@ function generateStyles(styles, themeName, theme) {
}
}


/*******************************************************************************
* Extarcting styles from a theme
* Iterate over the theme settings and write them off into the root JSON
* as either global styling or normal styling.
*/
function extractStyles(themeName, theme) {
generateThemeInfo(themeName, theme);
Expand All @@ -139,24 +201,27 @@ function extractStyles(themeName, theme) {
else {
generateStyles(settings[i], themeName, theme);
}

}
}

/*******************************************************************************
* Parsing the theme
* Parse the XML structure
*/
function parseTheme(themeXml, callback) {
var theme = plist.parse(themeXml);
callback(theme);
}

function printLoadingMessage(name) {

/*******************************************************************************
* Let the user know that the theme has been generated
*/
function printCompletedMessage(themeName) {
console.log([
'',
' __________________________________ ',
' ________| ',
' \\ | Converting theme: '+ name +' ',
' \\ | Converted theme: '+ themeName +'',
' \\ | ',
' / |__________________________________ ',
' /___________) ',
Expand All @@ -165,31 +230,41 @@ function printLoadingMessage(name) {
].join('\n'));
}


/*******************************************************************************
* Converting the theme
* Read the given theme file and send it off to be parsed.
* Once completed, send off the root JSON to be written to CSS.
*/
function convertTheme(name, themePath, outputDirectory) {
printLoadingMessage(name);
var srcTheme = fs.readFileSync(themePath, 'utf8');
function convertTheme(themeName, themePath, outputDirectory) {
var srcTheme = fs.readFileSync(__dirname + themePath, 'utf8');
parseTheme(srcTheme, function(theme) {
extractStyles(name, theme);
writeFile(root);
extractStyles(themeName, theme);
writeFile(root, themeName, outputDirectory, printCompletedMessage);
});
}


/*******************************************************************************
* Helper function for cleaning up the beginning slash
*/
function cleanPath(path) {
return '/' + path.replace(/^\//g, '');
}


/*******************************************************************************
* Processing the arguments from terminal
*/
if (process.argv.length > 1) {
var args = process.argv.splice(2);
if (args.length < 3) {
console.error('Usage: node main.js [theme_name, path/to/theme.tmTheme path/to/output/directory]');
if (args.length < 2) {
console.error('Usage: node main.js [themeName, pathToDirection, outputDirectory (OPTIONAL)]');
process.exit(1);
}
var name = args[0];
var themePath = args[1];
var outputDirectory = args[2];
convertTheme(name, themePath, outputDirectory);
var themeName = args[0];
var themePath = cleanPath(args[1]);
var outputDirectory = cleanPath(args[2]);
convertTheme(themeName, themePath, outputDirectory);
}


Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sublime-codeMirror-theme-converter",
"version": "1.0.0",
"description": "A simple theme covererter from Sublime to CodeMirror",
"name": "codeMirror-aceEditor-themes-generator",
"version": "0.1",
"description": "CodeMirror & Ace Editor themes converted from a GUI and/or Sublime Text & TextMate themes",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand All @@ -10,13 +10,14 @@
"sublime",
"codemirror",
"code mirror",
"theme"
"ace editor",
"textmate",
"sublime text"
],
"author": "Farhad Ghayour",
"license": "ISC",
"dependencies": {
"cssjson": "^2.1.3",
"plist": "^1.1.0",
"xml2js": "^0.4.4"
"plist": "^1.1.0"
}
}
4 changes: 4 additions & 0 deletions scopes/AceEditorSupportedScopes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*******************************************************************************
* Sublime/TextMate and Ace Editor (WIP)
*/
module.exports = {};
2 changes: 1 addition & 1 deletion supportedScopes.js → scopes/CodeMirrorSupportedScopes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Current supported scopes between Sublime + CodeMirror
* Current supported scopes between Sublime/TextMate and CodeMirror
*/
module.exports = {
/*
Expand Down
Loading

0 comments on commit 9c655e1

Please sign in to comment.