diff --git a/tool/add_mode.js b/tool/add_mode.js new file mode 100644 index 00000000..d8110923 --- /dev/null +++ b/tool/add_mode.js @@ -0,0 +1,101 @@ +var fs = require('fs'); +var lib = require('./lib'); +var path = require('path'); + +var args = process.argv.slice(2); + + +var displayName = args[0]; +var extRe = args[1]; +if (!displayName || ! extRe) { + console.log("Usage: ModeName ext1|ext2"); + process.exit(1); +} + +var name = lib.snakeCase(displayName).replace(/[^\w]/g, ""); + +/** demo **/ +var demoFileExt = extRe.split("|")[0] || name; +var demoFileName = demoFileExt[0] == "^" ? demoFileExt.substr(1) : name + "." + demoFileExt; +var demoFilePath = lib.AceRoot + "demo/kitchen-sink/docs/" + demoFileName; +fs.writeFileSync(demoFilePath, "TODO add a nice demo!", "utf8"); +console.log("Created demo file at: " + path.normalize(demoFilePath)); + +/** mode **/ +var template = fs.readFileSync(__dirname + "/mode.tmpl.js", "utf8"); +var modePath = lib.AceLib + "ace/mode/" + name + ".js"; +var text = lib.fillTemplate(template, { + languageHighlightFilename: name, + languagename: name, + lineCommentStart: "TODO", + blockCommentStart: "TODO", + blockCommentEnd: "TODO" +}); +fs.writeFileSync(modePath, text); +console.log("Created mode file at: " + path.normalize(modePath)); + +/** highlight rules **/ +template = fs.readFileSync(__dirname + "/mode_highlight_rules.tmpl.js", "utf8"); +var hlPath = lib.AceLib + "ace/mode/" + name + "_highlight_rules.js"; +template = template.replace(/\/\* THIS[\s\S]*?\*{3}\/\s*/, ""); +text = lib.fillTemplate(template, { + language: name, + languageTokens: '{\n\ + start: [{\n\ + token: "string.start",\n\ + regex: \'"\',\n\ + next: "qstring"\n\ + }],\n\ + qstring: [{\n\ + token: "escape",\n\ + regex: /\\\\./,\n\ + }, {\n\ + token: "string.end",\n\ + regex: \'"\',\n\ + next: "start"\n\ + }],\n\ + }' +}); +fs.writeFileSync(hlPath, text); +console.log("Created mode file at: " + path.normalize(hlPath)); + +/** snippets **/ +template = fs.readFileSync(__dirname + "/tmsnippets.tmpl.js", "utf8"); +var snipetsPath = lib.AceLib + "ace/snippets/" + name + ".js"; +text = lib.fillTemplate(template, { + languagename: name, + snippets: "" +}); +fs.writeFileSync(snipetsPath, text); +console.log("Created snippets file at: " + path.normalize(snipetsPath)); + +/** modelist **/ +var modelistPath = lib.AceLib + "ace/ext/modelist.js"; +var modelist = fs.readFileSync(modelistPath, "utf8").replace(/\r\n?/g, "\n"); +modelist = modelist.replace(/(supportedModes = {\n)([\s\S]*?)(\n^};)/m, function(_, m1, m2, m3) { + var langs = m2.split(/,\n/); + var offset = langs[0].trim().indexOf("["); + var padding = Array(Math.max(offset - displayName.length - 1, 0) + 1).join(" "); + var newLang = " " + displayName + ":" + padding + "[\"" + extRe + "\"]"; + langs = langs.concat(newLang).map(function(x) { + return { + value: x, + id: x.match(/[^"':\s]+/)[0].toLowerCase() + }; + }); + langs[langs.length - 1].isNew = true; + + langs = langs.filter(function(x) { + return x.id != name || x.isNew; + }); + langs = langs.sort(function(a, b) { + return a.id.localeCompare(b.id); + }).map(function(x) { + return x.value; + }); + + return m1 + langs.join(",\n") + m3; +}); +fs.writeFileSync(modelistPath, modelist, "utf8"); +console.log("Updated modelist at: " + path.normalize(modelistPath)); + diff --git a/tool/lib.js b/tool/lib.js index 605922e0..d7c0af26 100644 --- a/tool/lib.js +++ b/tool/lib.js @@ -1,38 +1,73 @@ var plist = require("plist"); var util = require("util"); +var url = require("url"); + +var https = require("https"); +var http = require("http"); + exports.parsePlist = function(themeXml, callback) { - var result = "" + var result = ""; plist.parseString(themeXml, function(_, theme) { result = theme[0]; callback && callback(theme[0]); }); return result; -} +}; exports.formatJSON = function(object, initialIndent) { - return util.inspect(object, false, 40).replace(/^/gm, initialIndent||"") - -} + return util.inspect(object, false, 40).replace(/^/gm, initialIndent||""); +}; exports.fillTemplate = function(template, replacements) { return template.replace(/%(.+?)%/g, function(str, m) { return replacements[m] || ""; }); -} +}; exports.hyphenate = function(str) { - return str.replace(/([A-Z])/g, "-$1").replace(/_/g, "-").toLowerCase(); -} + return str.replace(/([A-Z])/g, "-$1").replace(/[_\s\-]+/g, "-").toLowerCase(); +}; + +exports.camelCase = function(str) { + return str.replace(/[\-_\s]+(.?)/g, function(x, y) {return y.toUpperCase()}); +}; + +exports.snakeCase = function(str) { + return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[_\s\-]+/g, "_").toLowerCase(); +}; exports.quoteString = function(str) { return '"' + str.replace(/\\/, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\\n") + '"'; -} +}; exports.restoreJSONComments = function(objStr) { return objStr.replace(/^(\s*)comment: '(.*)'/gm, function(_, i, c) { - return i + "//" + c.replace(/\\n(\\t)*/g, "\n" + i + "//") + "\n" + i + return i + "//" + c.replace(/\\n(\\t)*/g, "\n" + i + "//") + "\n" + i; }).replace(/ \/\/ ERROR/g, '", // ERROR'); -} +}; + + +exports.download = function(href, callback) { + var options = url.parse(href); + var protocol = options.protocol === "https:" ? https : http; + console.log("connecting to " + options.host + " " + options.path); + var request = protocol.get(options, function(res) { + var data = ""; + res.setEncoding("utf-8"); + + res.on("data", function(chunk) { + data += chunk; + }); + + res.on("end", function(){ + callback(data); + }); + }); +}; + + +exports.AceRoot = __dirname + "/../"; +exports.AceLib = __dirname + "/../lib/"; diff --git a/tool/mode.tmpl.js b/tool/mode.tmpl.js index 98602dab..ff21c885 100644 --- a/tool/mode.tmpl.js +++ b/tool/mode.tmpl.js @@ -37,7 +37,6 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var TextMode = require("./text").Mode; -var Tokenizer = require("../tokenizer").Tokenizer; var %language%HighlightRules = require("./%languageHighlightFilename%_highlight_rules").%language%HighlightRules; // TODO: pick appropriate fold mode var FoldMode = require("./folding/cstyle").FoldMode; @@ -49,9 +48,10 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { - this.lineCommentStart = "//"; - this.blockComment = {start: "/*", end: "*/"}; + this.lineCommentStart = "%lineCommentStart%"; + this.blockComment = {start: "%blockCommentStart%", end: "%blockCommentEnd%"}; // Extra logic goes here. + this.$id = "ace/mode/%languageHighlightFilename%" }).call(Mode.prototype); exports.Mode = Mode;